jk-ferret 0.11.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +24 -0
- data/MIT-LICENSE +20 -0
- data/README +90 -0
- data/RELEASE_CHANGES +137 -0
- data/RELEASE_NOTES +60 -0
- data/Rakefile +443 -0
- data/TODO +109 -0
- data/TUTORIAL +231 -0
- data/bin/ferret-browser +79 -0
- data/ext/BZLIB_blocksort.c +1094 -0
- data/ext/BZLIB_bzlib.c +1578 -0
- data/ext/BZLIB_compress.c +672 -0
- data/ext/BZLIB_crctable.c +104 -0
- data/ext/BZLIB_decompress.c +626 -0
- data/ext/BZLIB_huffman.c +205 -0
- data/ext/BZLIB_randtable.c +84 -0
- data/ext/STEMMER_api.c +66 -0
- data/ext/STEMMER_libstemmer.c +93 -0
- data/ext/STEMMER_stem_ISO_8859_1_danish.c +337 -0
- data/ext/STEMMER_stem_ISO_8859_1_dutch.c +624 -0
- data/ext/STEMMER_stem_ISO_8859_1_english.c +1117 -0
- data/ext/STEMMER_stem_ISO_8859_1_finnish.c +762 -0
- data/ext/STEMMER_stem_ISO_8859_1_french.c +1246 -0
- data/ext/STEMMER_stem_ISO_8859_1_german.c +503 -0
- data/ext/STEMMER_stem_ISO_8859_1_hungarian.c +1230 -0
- data/ext/STEMMER_stem_ISO_8859_1_italian.c +1065 -0
- data/ext/STEMMER_stem_ISO_8859_1_norwegian.c +297 -0
- data/ext/STEMMER_stem_ISO_8859_1_porter.c +749 -0
- data/ext/STEMMER_stem_ISO_8859_1_portuguese.c +1017 -0
- data/ext/STEMMER_stem_ISO_8859_1_spanish.c +1093 -0
- data/ext/STEMMER_stem_ISO_8859_1_swedish.c +307 -0
- data/ext/STEMMER_stem_ISO_8859_2_romanian.c +998 -0
- data/ext/STEMMER_stem_KOI8_R_russian.c +700 -0
- data/ext/STEMMER_stem_UTF_8_danish.c +339 -0
- data/ext/STEMMER_stem_UTF_8_dutch.c +634 -0
- data/ext/STEMMER_stem_UTF_8_english.c +1125 -0
- data/ext/STEMMER_stem_UTF_8_finnish.c +768 -0
- data/ext/STEMMER_stem_UTF_8_french.c +1256 -0
- data/ext/STEMMER_stem_UTF_8_german.c +509 -0
- data/ext/STEMMER_stem_UTF_8_hungarian.c +1234 -0
- data/ext/STEMMER_stem_UTF_8_italian.c +1073 -0
- data/ext/STEMMER_stem_UTF_8_norwegian.c +299 -0
- data/ext/STEMMER_stem_UTF_8_porter.c +755 -0
- data/ext/STEMMER_stem_UTF_8_portuguese.c +1023 -0
- data/ext/STEMMER_stem_UTF_8_romanian.c +1004 -0
- data/ext/STEMMER_stem_UTF_8_russian.c +694 -0
- data/ext/STEMMER_stem_UTF_8_spanish.c +1097 -0
- data/ext/STEMMER_stem_UTF_8_swedish.c +309 -0
- data/ext/STEMMER_stem_UTF_8_turkish.c +2205 -0
- data/ext/STEMMER_utilities.c +478 -0
- data/ext/analysis.c +1710 -0
- data/ext/analysis.h +266 -0
- data/ext/api.h +26 -0
- data/ext/array.c +125 -0
- data/ext/array.h +62 -0
- data/ext/bitvector.c +96 -0
- data/ext/bitvector.h +594 -0
- data/ext/bzlib.h +282 -0
- data/ext/bzlib_private.h +503 -0
- data/ext/compound_io.c +384 -0
- data/ext/config.h +52 -0
- data/ext/document.c +159 -0
- data/ext/document.h +63 -0
- data/ext/except.c +102 -0
- data/ext/except.h +176 -0
- data/ext/extconf.rb +15 -0
- data/ext/ferret.c +416 -0
- data/ext/ferret.h +94 -0
- data/ext/field_index.c +262 -0
- data/ext/field_index.h +52 -0
- data/ext/filter.c +157 -0
- data/ext/fs_store.c +493 -0
- data/ext/global.c +458 -0
- data/ext/global.h +302 -0
- data/ext/hash.c +524 -0
- data/ext/hash.h +515 -0
- data/ext/hashset.c +192 -0
- data/ext/hashset.h +215 -0
- data/ext/header.h +58 -0
- data/ext/helper.c +63 -0
- data/ext/helper.h +21 -0
- data/ext/index.c +6804 -0
- data/ext/index.h +935 -0
- data/ext/internal.h +1019 -0
- data/ext/lang.c +10 -0
- data/ext/lang.h +68 -0
- data/ext/libstemmer.h +79 -0
- data/ext/mempool.c +88 -0
- data/ext/mempool.h +43 -0
- data/ext/modules.h +190 -0
- data/ext/multimapper.c +351 -0
- data/ext/multimapper.h +60 -0
- data/ext/posh.c +1006 -0
- data/ext/posh.h +973 -0
- data/ext/priorityqueue.c +149 -0
- data/ext/priorityqueue.h +155 -0
- data/ext/q_boolean.c +1621 -0
- data/ext/q_const_score.c +162 -0
- data/ext/q_filtered_query.c +212 -0
- data/ext/q_fuzzy.c +280 -0
- data/ext/q_match_all.c +149 -0
- data/ext/q_multi_term.c +673 -0
- data/ext/q_parser.c +3103 -0
- data/ext/q_phrase.c +1206 -0
- data/ext/q_prefix.c +98 -0
- data/ext/q_range.c +682 -0
- data/ext/q_span.c +2390 -0
- data/ext/q_term.c +337 -0
- data/ext/q_wildcard.c +167 -0
- data/ext/r_analysis.c +2626 -0
- data/ext/r_index.c +3468 -0
- data/ext/r_qparser.c +635 -0
- data/ext/r_search.c +4490 -0
- data/ext/r_store.c +513 -0
- data/ext/r_utils.c +1131 -0
- data/ext/ram_store.c +476 -0
- data/ext/scanner.c +895 -0
- data/ext/scanner.h +36 -0
- data/ext/scanner_mb.c +6701 -0
- data/ext/scanner_utf8.c +4415 -0
- data/ext/search.c +1864 -0
- data/ext/search.h +953 -0
- data/ext/similarity.c +151 -0
- data/ext/similarity.h +89 -0
- data/ext/sort.c +786 -0
- data/ext/stem_ISO_8859_1_danish.h +16 -0
- data/ext/stem_ISO_8859_1_dutch.h +16 -0
- data/ext/stem_ISO_8859_1_english.h +16 -0
- data/ext/stem_ISO_8859_1_finnish.h +16 -0
- data/ext/stem_ISO_8859_1_french.h +16 -0
- data/ext/stem_ISO_8859_1_german.h +16 -0
- data/ext/stem_ISO_8859_1_hungarian.h +16 -0
- data/ext/stem_ISO_8859_1_italian.h +16 -0
- data/ext/stem_ISO_8859_1_norwegian.h +16 -0
- data/ext/stem_ISO_8859_1_porter.h +16 -0
- data/ext/stem_ISO_8859_1_portuguese.h +16 -0
- data/ext/stem_ISO_8859_1_spanish.h +16 -0
- data/ext/stem_ISO_8859_1_swedish.h +16 -0
- data/ext/stem_ISO_8859_2_romanian.h +16 -0
- data/ext/stem_KOI8_R_russian.h +16 -0
- data/ext/stem_UTF_8_danish.h +16 -0
- data/ext/stem_UTF_8_dutch.h +16 -0
- data/ext/stem_UTF_8_english.h +16 -0
- data/ext/stem_UTF_8_finnish.h +16 -0
- data/ext/stem_UTF_8_french.h +16 -0
- data/ext/stem_UTF_8_german.h +16 -0
- data/ext/stem_UTF_8_hungarian.h +16 -0
- data/ext/stem_UTF_8_italian.h +16 -0
- data/ext/stem_UTF_8_norwegian.h +16 -0
- data/ext/stem_UTF_8_porter.h +16 -0
- data/ext/stem_UTF_8_portuguese.h +16 -0
- data/ext/stem_UTF_8_romanian.h +16 -0
- data/ext/stem_UTF_8_russian.h +16 -0
- data/ext/stem_UTF_8_spanish.h +16 -0
- data/ext/stem_UTF_8_swedish.h +16 -0
- data/ext/stem_UTF_8_turkish.h +16 -0
- data/ext/stopwords.c +410 -0
- data/ext/store.c +698 -0
- data/ext/store.h +799 -0
- data/ext/symbol.c +10 -0
- data/ext/symbol.h +23 -0
- data/ext/term_vectors.c +73 -0
- data/ext/threading.h +31 -0
- data/ext/win32.h +62 -0
- data/lib/ferret.rb +30 -0
- data/lib/ferret/browser.rb +246 -0
- data/lib/ferret/browser/s/global.js +192 -0
- data/lib/ferret/browser/s/style.css +148 -0
- data/lib/ferret/browser/views/document/list.rhtml +49 -0
- data/lib/ferret/browser/views/document/show.rhtml +27 -0
- data/lib/ferret/browser/views/error/index.rhtml +7 -0
- data/lib/ferret/browser/views/help/index.rhtml +8 -0
- data/lib/ferret/browser/views/home/index.rhtml +29 -0
- data/lib/ferret/browser/views/layout.rhtml +22 -0
- data/lib/ferret/browser/views/term-vector/index.rhtml +4 -0
- data/lib/ferret/browser/views/term/index.rhtml +199 -0
- data/lib/ferret/browser/views/term/termdocs.rhtml +1 -0
- data/lib/ferret/browser/webrick.rb +14 -0
- data/lib/ferret/document.rb +130 -0
- data/lib/ferret/field_infos.rb +44 -0
- data/lib/ferret/field_symbol.rb +87 -0
- data/lib/ferret/index.rb +973 -0
- data/lib/ferret/number_tools.rb +157 -0
- data/lib/ferret/version.rb +3 -0
- data/setup.rb +1555 -0
- data/test/long_running/largefile/tc_largefile.rb +46 -0
- data/test/test_all.rb +5 -0
- data/test/test_helper.rb +29 -0
- data/test/test_installed.rb +1 -0
- data/test/threading/number_to_spoken.rb +132 -0
- data/test/threading/thread_safety_index_test.rb +88 -0
- data/test/threading/thread_safety_read_write_test.rb +73 -0
- data/test/threading/thread_safety_test.rb +133 -0
- data/test/unit/analysis/tc_analyzer.rb +550 -0
- data/test/unit/analysis/tc_token_stream.rb +653 -0
- data/test/unit/index/tc_index.rb +867 -0
- data/test/unit/index/tc_index_reader.rb +699 -0
- data/test/unit/index/tc_index_writer.rb +447 -0
- data/test/unit/index/th_doc.rb +332 -0
- data/test/unit/query_parser/tc_query_parser.rb +238 -0
- data/test/unit/search/tc_filter.rb +156 -0
- data/test/unit/search/tc_fuzzy_query.rb +147 -0
- data/test/unit/search/tc_index_searcher.rb +67 -0
- data/test/unit/search/tc_multi_searcher.rb +128 -0
- data/test/unit/search/tc_multiple_search_requests.rb +58 -0
- data/test/unit/search/tc_search_and_sort.rb +179 -0
- data/test/unit/search/tc_sort.rb +49 -0
- data/test/unit/search/tc_sort_field.rb +27 -0
- data/test/unit/search/tc_spans.rb +190 -0
- data/test/unit/search/tm_searcher.rb +436 -0
- data/test/unit/store/tc_fs_store.rb +115 -0
- data/test/unit/store/tc_ram_store.rb +35 -0
- data/test/unit/store/tm_store.rb +34 -0
- data/test/unit/store/tm_store_lock.rb +68 -0
- data/test/unit/tc_document.rb +81 -0
- data/test/unit/tc_field_symbol.rb +26 -0
- data/test/unit/ts_analysis.rb +2 -0
- data/test/unit/ts_index.rb +2 -0
- data/test/unit/ts_largefile.rb +4 -0
- data/test/unit/ts_query_parser.rb +2 -0
- data/test/unit/ts_search.rb +2 -0
- data/test/unit/ts_store.rb +2 -0
- data/test/unit/ts_utils.rb +2 -0
- data/test/unit/utils/tc_bit_vector.rb +295 -0
- data/test/unit/utils/tc_number_tools.rb +117 -0
- data/test/unit/utils/tc_priority_queue.rb +106 -0
- data/test/utils/content_generator.rb +226 -0
- metadata +319 -0
data/ext/symbol.c
ADDED
data/ext/symbol.h
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#ifndef FRT_SYMBOL_H
|
2
|
+
#define FRT_SYMBOL_H
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
|
6
|
+
typedef void *FrtSymbol;
|
7
|
+
|
8
|
+
VALUE rb_id2str(ID id);
|
9
|
+
#define frt_symbol_init()
|
10
|
+
#define frt_intern(str) (FrtSymbol)rb_intern(str)
|
11
|
+
extern FrtSymbol frt_intern_and_free(char *str);
|
12
|
+
|
13
|
+
#define FRT_I frt_intern
|
14
|
+
#define FRT_InF frt_intern_and_free
|
15
|
+
#define FRT_S(_sym) rb_id2name((ID)_sym)
|
16
|
+
|
17
|
+
#define FSYM2SYM(_sym) ID2SYM((ID)_sym)
|
18
|
+
#define SYM2FSYM(_sym) (FrtSymbol)SYM2ID(_sym)
|
19
|
+
|
20
|
+
#define frt_sym_hash(sym) frt_str_hash(rb_id2name((ID)sym))
|
21
|
+
#define frt_sym_len(sym) strlen(rb_id2name((ID)sym))
|
22
|
+
|
23
|
+
#endif
|
data/ext/term_vectors.c
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
#include <string.h>
|
2
|
+
#include "index.h"
|
3
|
+
#include "array.h"
|
4
|
+
#include "helper.h"
|
5
|
+
#include "symbol.h"
|
6
|
+
#include "internal.h"
|
7
|
+
|
8
|
+
/****************************************************************************
|
9
|
+
*
|
10
|
+
* TermVector
|
11
|
+
*
|
12
|
+
****************************************************************************/
|
13
|
+
|
14
|
+
void tv_destroy(TermVector *tv)
|
15
|
+
{
|
16
|
+
int i = tv->term_cnt;
|
17
|
+
while (i > 0) {
|
18
|
+
i--;
|
19
|
+
free(tv->terms[i].text);
|
20
|
+
free(tv->terms[i].positions);
|
21
|
+
}
|
22
|
+
free(tv->offsets);
|
23
|
+
free(tv->terms);
|
24
|
+
free(tv);
|
25
|
+
}
|
26
|
+
|
27
|
+
int tv_scan_to_term_index(TermVector *tv, const char *term)
|
28
|
+
{
|
29
|
+
int lo = 0; /* search starts array */
|
30
|
+
int hi = tv->term_cnt - 1; /* for 1st element < n, return its index */
|
31
|
+
int mid;
|
32
|
+
int cmp;
|
33
|
+
char *mid_term;
|
34
|
+
|
35
|
+
while (hi >= lo) {
|
36
|
+
mid = (lo + hi) >> 1;
|
37
|
+
mid_term = tv->terms[mid].text;
|
38
|
+
cmp = strcmp(term, mid_term);
|
39
|
+
if (cmp < 0) {
|
40
|
+
hi = mid - 1;
|
41
|
+
}
|
42
|
+
else if (cmp > 0) {
|
43
|
+
lo = mid + 1;
|
44
|
+
}
|
45
|
+
else { /* found a match */
|
46
|
+
return mid;
|
47
|
+
}
|
48
|
+
}
|
49
|
+
return lo;
|
50
|
+
}
|
51
|
+
|
52
|
+
int tv_get_term_index(TermVector *tv, const char *term)
|
53
|
+
{
|
54
|
+
int index = tv_scan_to_term_index(tv, term);
|
55
|
+
if (index < tv->term_cnt && (0 == strcmp(term, tv->terms[index].text))) {
|
56
|
+
/* found term */
|
57
|
+
return index;
|
58
|
+
}
|
59
|
+
else {
|
60
|
+
return -1;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
TVTerm *tv_get_tv_term(TermVector *tv, const char *term)
|
65
|
+
{
|
66
|
+
int index = tv_get_term_index(tv, term);
|
67
|
+
if (index >= 0) {
|
68
|
+
return &(tv->terms[index]);
|
69
|
+
}
|
70
|
+
else {
|
71
|
+
return NULL;
|
72
|
+
}
|
73
|
+
}
|
data/ext/threading.h
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#ifndef FRT_THREADING_H
|
2
|
+
#define FRT_THREADING_H
|
3
|
+
|
4
|
+
#include "hash.h"
|
5
|
+
#define UNTHREADED 1
|
6
|
+
|
7
|
+
typedef void * frt_mutex_t;
|
8
|
+
typedef struct FrtHash *frt_thread_key_t;
|
9
|
+
typedef int frt_thread_once_t;
|
10
|
+
#define FRT_MUTEX_INITIALIZER NULL
|
11
|
+
#define FRT_MUTEX_RECURSIVE_INITIALIZER NULL
|
12
|
+
#define FRT_THREAD_ONCE_INIT 1;
|
13
|
+
#define frt_mutex_init(a, b)
|
14
|
+
#define frt_mutex_lock(a)
|
15
|
+
#define frt_mutex_trylock(a)
|
16
|
+
#define frt_mutex_unlock(a)
|
17
|
+
#define frt_mutex_destroy(a)
|
18
|
+
#define frt_thread_key_create(a, b) frb_thread_key_create(a, b)
|
19
|
+
#define frt_thread_key_delete(a) frb_thread_key_delete(a)
|
20
|
+
#define frt_thread_setspecific(a, b) frb_thread_setspecific(a, b)
|
21
|
+
#define frt_thread_getspecific(a) frb_thread_getspecific(a)
|
22
|
+
#define frt_thread_exit(a)
|
23
|
+
#define frt_thread_once(a, b) frb_thread_once(a, b)
|
24
|
+
|
25
|
+
void frb_thread_once(int *once_control, void (*init_routine)(void));
|
26
|
+
void frb_thread_key_create(frt_thread_key_t *key, frt_free_ft destroy);
|
27
|
+
void frb_thread_key_delete(frt_thread_key_t key);
|
28
|
+
void frb_thread_setspecific(frt_thread_key_t key, const void *pointer);
|
29
|
+
void *frb_thread_getspecific(frt_thread_key_t key);
|
30
|
+
|
31
|
+
#endif
|
data/ext/win32.h
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
#ifndef FRT_WIN32_H
|
2
|
+
#define FRT_WIN32_H
|
3
|
+
|
4
|
+
#ifdef __cplusplus
|
5
|
+
extern "C" {
|
6
|
+
#endif
|
7
|
+
|
8
|
+
#include "global.h"
|
9
|
+
#include <io.h>
|
10
|
+
|
11
|
+
struct dirent
|
12
|
+
{
|
13
|
+
char *d_name;
|
14
|
+
};
|
15
|
+
|
16
|
+
typedef struct DIR
|
17
|
+
{
|
18
|
+
struct _finddata_t find_data;
|
19
|
+
struct dirent de;
|
20
|
+
long handle;
|
21
|
+
} DIR;
|
22
|
+
|
23
|
+
DIR *opendir(const char *dirname)
|
24
|
+
{
|
25
|
+
DIR *d = FRT_ALLOC_AND_ZERO(DIR);
|
26
|
+
char dirname_buf[FRT_MAX_FILE_PATH];
|
27
|
+
long ff_res;
|
28
|
+
sprintf(dirname_buf, "%s\\*", dirname);
|
29
|
+
ff_res = _findfirst(dirname_buf, &d->find_data);
|
30
|
+
if (ff_res < 0) {
|
31
|
+
free(d);
|
32
|
+
d = NULL;
|
33
|
+
} else {
|
34
|
+
d->de.d_name = NULL;
|
35
|
+
d->handle = ff_res;
|
36
|
+
}
|
37
|
+
return d;
|
38
|
+
}
|
39
|
+
|
40
|
+
struct dirent *readdir(DIR *d)
|
41
|
+
{
|
42
|
+
/* _findfirst already returned so do _findnext */
|
43
|
+
if (d->de.d_name != NULL) {
|
44
|
+
if (_findnext(d->handle, &d->find_data) < 0) {
|
45
|
+
return NULL;
|
46
|
+
}
|
47
|
+
}
|
48
|
+
d->de.d_name = d->find_data.name;
|
49
|
+
return &d->de;
|
50
|
+
}
|
51
|
+
|
52
|
+
void closedir(DIR *d)
|
53
|
+
{
|
54
|
+
_findclose(d->handle);
|
55
|
+
free(d);
|
56
|
+
}
|
57
|
+
|
58
|
+
#ifdef __cplusplus
|
59
|
+
} // extern "C"
|
60
|
+
#endif
|
61
|
+
|
62
|
+
#endif
|
data/lib/ferret.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2005 David Balmain
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
# :include: ../TUTORIAL
|
24
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__), "../ext"))
|
25
|
+
require 'ferret_ext'
|
26
|
+
require 'ferret/version'
|
27
|
+
require 'ferret/document'
|
28
|
+
require 'ferret/index'
|
29
|
+
require 'ferret/field_infos'
|
30
|
+
require 'ferret/field_symbol'
|
@@ -0,0 +1,246 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
|
4
|
+
module Ferret::Browser
|
5
|
+
class Delegator
|
6
|
+
def initialize(reader, path)
|
7
|
+
@reader, @path = reader, path
|
8
|
+
end
|
9
|
+
|
10
|
+
def run(env)
|
11
|
+
controller, action, args = :home, :index, nil
|
12
|
+
query_string = env['QUERY_STRING']||''
|
13
|
+
params = parse_query_string(query_string)
|
14
|
+
req_path = env['PATH_INFO'].gsub(/\/+/, '/')
|
15
|
+
case req_path
|
16
|
+
when '/'
|
17
|
+
# nothing to do
|
18
|
+
when /^\/?([-a-zA-Z]+)\/?$/
|
19
|
+
controller = $1
|
20
|
+
when /^\/?([-a-zA-Z]+)\/([-a-zA-Z]+)\/?(.*)?$/
|
21
|
+
controller = $1
|
22
|
+
action = $2
|
23
|
+
args = $3
|
24
|
+
else
|
25
|
+
controller = :error
|
26
|
+
args = req_path
|
27
|
+
end
|
28
|
+
controller_vars = {
|
29
|
+
:params => params,
|
30
|
+
:req_path => req_path,
|
31
|
+
:query_string => query_string,
|
32
|
+
}
|
33
|
+
delegate(controller, action, args, controller_vars)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def delegate(controller, action, args, controller_vars)
|
39
|
+
begin
|
40
|
+
controller = to_const(controller, 'Controller').
|
41
|
+
new(@reader, @path, controller_vars)
|
42
|
+
controller.send(action, args)
|
43
|
+
rescue Exception => e
|
44
|
+
puts e.to_s
|
45
|
+
controller_vars[:params][:error] = e
|
46
|
+
ErrorController.new(@reader, @path, controller_vars).index
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_const(str, suffix='')
|
51
|
+
Ferret::Browser.const_get(str.to_s.split('-').
|
52
|
+
map {|w| w.capitalize}.join('') + suffix)
|
53
|
+
end
|
54
|
+
|
55
|
+
# from _why's camping
|
56
|
+
def unescape_uri(s)
|
57
|
+
s.tr('+', ' ').gsub(/%([\da-f]{2})/in){[$1].pack('H*')}
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_query_string(query_string, delim = '&;')
|
61
|
+
m = proc {|_,o,n| o.update(n, &m) rescue ([*o] << n)}
|
62
|
+
(query_string||'').split(/[#{delim}] */n).
|
63
|
+
inject({}) { |hash, param| key, val = unescape_uri(param).split('=',2)
|
64
|
+
hash.update(key.split(/[\]\[]+/).reverse.
|
65
|
+
inject(val) { |x,i| Hash[i,x] }, &m)
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
module ViewHelper
|
71
|
+
# truncates the string at the first space after +len+ characters
|
72
|
+
def truncate(str, len = 80)
|
73
|
+
if str and str.length > len and (add = str[len..-1].index(' '))
|
74
|
+
str = str[0, len + add] + '…'
|
75
|
+
end
|
76
|
+
str
|
77
|
+
end
|
78
|
+
|
79
|
+
def tick_or_cross(t)
|
80
|
+
"<img src=\"/s/i/#{t ? 'tick' : 'cross'}.png\" alt=\"#{t ? 'yes' : 'no'}\"/>"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class Controller
|
85
|
+
include ViewHelper
|
86
|
+
APP_DIR = File.expand_path(File.join(File.dirname(__FILE__), "browser/"))
|
87
|
+
STATIC_DIR = File.expand_path(File.join(APP_DIR, "s/"))
|
88
|
+
|
89
|
+
def initialize(reader, path, vars)
|
90
|
+
@reader = reader
|
91
|
+
@path = path
|
92
|
+
vars.each_pair {|key, val| instance_eval("@#{key} = val")}
|
93
|
+
@controller_path = pathify(self.class.to_s.gsub(/.*:/, ''))
|
94
|
+
end
|
95
|
+
|
96
|
+
def method_missing(meth_id, *args)
|
97
|
+
render(:action => meth_id)
|
98
|
+
end
|
99
|
+
|
100
|
+
protected
|
101
|
+
|
102
|
+
def load_page(page)
|
103
|
+
File.read(File.join(APP_DIR, page))
|
104
|
+
end
|
105
|
+
|
106
|
+
def render(options = {})
|
107
|
+
options = {
|
108
|
+
:controller => @controller_path,
|
109
|
+
:action => :index,
|
110
|
+
:status => 200,
|
111
|
+
:content_type => 'text/html',
|
112
|
+
:env => nil,
|
113
|
+
:layout => 'views/layout.rhtml',
|
114
|
+
}.update(options)
|
115
|
+
|
116
|
+
path = "views/#{options[:controller]}/#{options[:action]}.rhtml"
|
117
|
+
content = ERB.new(load_page(path)).result(lambda{})
|
118
|
+
if options[:layout]
|
119
|
+
content = ERB.new(load_page(options[:layout])).result(lambda{})
|
120
|
+
end
|
121
|
+
|
122
|
+
return options[:status], options[:content_type], content
|
123
|
+
end
|
124
|
+
|
125
|
+
# takes an optional block to set optional attributes in the links
|
126
|
+
def paginate(idx, max, url, &b)
|
127
|
+
return '' if max == 0
|
128
|
+
url = url.gsub(%r{^/?(.*?)/?$}, '\1')
|
129
|
+
b ||= lambda{}
|
130
|
+
link = lambda {|*args|
|
131
|
+
i, title, text = args
|
132
|
+
"<a href=\"/#{url}/#{i}#{'?' + @query_string if @query_string}\" " +
|
133
|
+
"#{'onclick="return false;"' if (i == idx)} " +
|
134
|
+
"class=\"#{'disabled ' if (i == idx)}#{b.call(i)}\" " +
|
135
|
+
"title=\"#{title||"Go to page #{i}"}\">#{text||i}</a>"
|
136
|
+
}
|
137
|
+
res = '<div class="nav">'
|
138
|
+
if (idx > 0)
|
139
|
+
res << link.call(idx - 1, "Go to previous page", "« Previous")
|
140
|
+
else
|
141
|
+
res << "<a href=\"/#{url}/0\" onclick=\"return false;\" " +
|
142
|
+
"class=\"disabled\" title=\"Disabled\">« Previous</a>"
|
143
|
+
end
|
144
|
+
if idx < 10
|
145
|
+
idx.times {|i| res << link.call(i)}
|
146
|
+
else
|
147
|
+
(0..2).each {|i| res << link.call(i)}
|
148
|
+
res << ' … '
|
149
|
+
((idx-4)...idx).each {|i| res << link.call(i)}
|
150
|
+
end
|
151
|
+
res << link.call(idx, 'Current Page')
|
152
|
+
if idx > (max - 10)
|
153
|
+
((idx+1)...max).each {|i| res << link.call(i)}
|
154
|
+
else
|
155
|
+
((idx+1)..(idx+4)).each {|i| res << link.call(i)}
|
156
|
+
res << ' … '
|
157
|
+
((max-3)...max).each {|i| res << link.call(i)}
|
158
|
+
end
|
159
|
+
if (idx < (max - 1))
|
160
|
+
res << link.call(idx + 1, "Go to next page", "Next »")
|
161
|
+
else
|
162
|
+
res << "<a href=\"/#{url}/#{max-1}\" onclick=\"return false;\" " +
|
163
|
+
"class=\"disabled\" title=\"Disabled\"}\">Next »</a>"
|
164
|
+
end
|
165
|
+
res << '</div>'
|
166
|
+
end
|
167
|
+
private
|
168
|
+
|
169
|
+
def pathify(str)
|
170
|
+
str.gsub(/Controller$/, '').gsub(/([a-z])([A-Z])/) {"#{$1}-#{$2}"}.downcase
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
class ErrorController < Controller
|
175
|
+
def index
|
176
|
+
render(:status => 404)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
class HomeController < Controller
|
181
|
+
end
|
182
|
+
|
183
|
+
class DocumentController < Controller
|
184
|
+
def list(page = 0)
|
185
|
+
@page = (page||0).to_i
|
186
|
+
@page_size = @params[:page_size]||10
|
187
|
+
@first = @page * @page_size
|
188
|
+
@last = [@reader.max_doc, (@page + 1) * @page_size].min
|
189
|
+
render(:action => :list)
|
190
|
+
end
|
191
|
+
alias :index :list
|
192
|
+
|
193
|
+
def show(doc_id)
|
194
|
+
doc_id = @params['doc_id']||doc_id||'0'
|
195
|
+
if doc_id !~ /^\d+$/
|
196
|
+
raise ArgumentError.new("invalid document number '#{doc_id}'")
|
197
|
+
end
|
198
|
+
@doc_id = doc_id.to_i
|
199
|
+
@doc = @reader[@doc_id].load unless @reader.deleted?(@doc_id)
|
200
|
+
render(:action => :show)
|
201
|
+
end
|
202
|
+
|
203
|
+
private
|
204
|
+
|
205
|
+
def choose_document(doc_id='')
|
206
|
+
<<-EOF
|
207
|
+
<form action="" method="get" onsubmit="location.href='/document/show/' + document.getElementById('doc_id').value;return false;">
|
208
|
+
<label for="doc_id">Go to document:
|
209
|
+
<input type="text" id="doc_id" name="doc_id" size="4" value="#{@doc_id}"/>
|
210
|
+
</label>
|
211
|
+
</form>
|
212
|
+
EOF
|
213
|
+
end
|
214
|
+
|
215
|
+
def paginate_docs
|
216
|
+
paginate(@doc_id, @reader.max_doc, '/document/show/') {|i|
|
217
|
+
'deleted' if @reader.deleted?(i)
|
218
|
+
}
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
class TermController < Controller
|
223
|
+
def show(field)
|
224
|
+
if field and field.length > 0
|
225
|
+
@field = field.to_sym
|
226
|
+
@terms = @reader.terms(@field).to_json(:fast)
|
227
|
+
end
|
228
|
+
render(:action => :index)
|
229
|
+
end
|
230
|
+
|
231
|
+
def termdocs(args)
|
232
|
+
args = args.split('/')
|
233
|
+
@field = args.shift.intern
|
234
|
+
@term = args.join('/')
|
235
|
+
render(:action => :termdocs,
|
236
|
+
:content_type => 'text/plain',
|
237
|
+
:layout => false)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
class TermVectorController < Controller
|
242
|
+
end
|
243
|
+
|
244
|
+
class HelpController < Controller
|
245
|
+
end
|
246
|
+
end
|