kpumuk-rlibsphinxclient 0.2.0

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.
Files changed (77) hide show
  1. data/CHANGELOG +0 -0
  2. data/Manifest +75 -0
  3. data/README.rdoc +149 -0
  4. data/Rakefile +33 -0
  5. data/ext/extconf.rb +20 -0
  6. data/ext/rlibsphinxclient.i +314 -0
  7. data/ext/rlibsphinxclient_wrap.c +5931 -0
  8. data/init.rb +1 -0
  9. data/lib/sphinx/client.rb +1070 -0
  10. data/lib/sphinx/fast_client.rb +184 -0
  11. data/lib/sphinx/request.rb +49 -0
  12. data/lib/sphinx/response.rb +69 -0
  13. data/lib/sphinx/safe_executor.rb +11 -0
  14. data/lib/sphinx/timeout.rb +9 -0
  15. data/lib/sphinx.rb +22 -0
  16. data/rlibsphinxclient.gemspec +35 -0
  17. data/spec/client_response_spec.rb +135 -0
  18. data/spec/client_spec.rb +548 -0
  19. data/spec/fixtures/default_search.php +8 -0
  20. data/spec/fixtures/default_search_index.php +8 -0
  21. data/spec/fixtures/excerpt_custom.php +11 -0
  22. data/spec/fixtures/excerpt_default.php +8 -0
  23. data/spec/fixtures/excerpt_flags.php +11 -0
  24. data/spec/fixtures/field_weights.php +9 -0
  25. data/spec/fixtures/filter.php +9 -0
  26. data/spec/fixtures/filter_exclude.php +9 -0
  27. data/spec/fixtures/filter_float_range.php +9 -0
  28. data/spec/fixtures/filter_float_range_exclude.php +9 -0
  29. data/spec/fixtures/filter_range.php +9 -0
  30. data/spec/fixtures/filter_range_exclude.php +9 -0
  31. data/spec/fixtures/filter_ranges.php +10 -0
  32. data/spec/fixtures/filters.php +10 -0
  33. data/spec/fixtures/filters_different.php +13 -0
  34. data/spec/fixtures/geo_anchor.php +9 -0
  35. data/spec/fixtures/group_by_attr.php +9 -0
  36. data/spec/fixtures/group_by_attrpair.php +9 -0
  37. data/spec/fixtures/group_by_day.php +9 -0
  38. data/spec/fixtures/group_by_day_sort.php +9 -0
  39. data/spec/fixtures/group_by_month.php +9 -0
  40. data/spec/fixtures/group_by_week.php +9 -0
  41. data/spec/fixtures/group_by_year.php +9 -0
  42. data/spec/fixtures/group_distinct.php +10 -0
  43. data/spec/fixtures/id_range.php +9 -0
  44. data/spec/fixtures/id_range64.php +9 -0
  45. data/spec/fixtures/index_weights.php +9 -0
  46. data/spec/fixtures/keywords.php +8 -0
  47. data/spec/fixtures/limits.php +9 -0
  48. data/spec/fixtures/limits_cutoff.php +9 -0
  49. data/spec/fixtures/limits_max.php +9 -0
  50. data/spec/fixtures/limits_max_cutoff.php +9 -0
  51. data/spec/fixtures/match_all.php +9 -0
  52. data/spec/fixtures/match_any.php +9 -0
  53. data/spec/fixtures/match_boolean.php +9 -0
  54. data/spec/fixtures/match_extended.php +9 -0
  55. data/spec/fixtures/match_extended2.php +9 -0
  56. data/spec/fixtures/match_fullscan.php +9 -0
  57. data/spec/fixtures/match_phrase.php +9 -0
  58. data/spec/fixtures/max_query_time.php +9 -0
  59. data/spec/fixtures/miltiple_queries.php +12 -0
  60. data/spec/fixtures/ranking_bm25.php +9 -0
  61. data/spec/fixtures/ranking_none.php +9 -0
  62. data/spec/fixtures/ranking_proximity_bm25.php +9 -0
  63. data/spec/fixtures/ranking_wordcount.php +9 -0
  64. data/spec/fixtures/retries.php +9 -0
  65. data/spec/fixtures/retries_delay.php +9 -0
  66. data/spec/fixtures/sort_attr_asc.php +9 -0
  67. data/spec/fixtures/sort_attr_desc.php +9 -0
  68. data/spec/fixtures/sort_expr.php +9 -0
  69. data/spec/fixtures/sort_extended.php +9 -0
  70. data/spec/fixtures/sort_relevance.php +9 -0
  71. data/spec/fixtures/sort_time_segments.php +9 -0
  72. data/spec/fixtures/sphinxapi.php +1181 -0
  73. data/spec/fixtures/update_attributes.php +8 -0
  74. data/spec/fixtures/weights.php +9 -0
  75. data/spec/sphinx/sphinx.conf +67 -0
  76. data/spec/sphinx/sphinx_test.sql +86 -0
  77. metadata +153 -0
data/CHANGELOG ADDED
File without changes
data/Manifest ADDED
@@ -0,0 +1,75 @@
1
+ CHANGELOG
2
+ ext/extconf.rb
3
+ ext/rlibsphinxclient.i
4
+ ext/rlibsphinxclient_wrap.c
5
+ init.rb
6
+ lib/sphinx/client.rb
7
+ lib/sphinx/fast_client.rb
8
+ lib/sphinx/request.rb
9
+ lib/sphinx/response.rb
10
+ lib/sphinx/safe_executor.rb
11
+ lib/sphinx/timeout.rb
12
+ lib/sphinx.rb
13
+ Manifest
14
+ Rakefile
15
+ README.rdoc
16
+ spec/client_response_spec.rb
17
+ spec/client_spec.rb
18
+ spec/fixtures/default_search.php
19
+ spec/fixtures/default_search_index.php
20
+ spec/fixtures/excerpt_custom.php
21
+ spec/fixtures/excerpt_default.php
22
+ spec/fixtures/excerpt_flags.php
23
+ spec/fixtures/field_weights.php
24
+ spec/fixtures/filter.php
25
+ spec/fixtures/filter_exclude.php
26
+ spec/fixtures/filter_float_range.php
27
+ spec/fixtures/filter_float_range_exclude.php
28
+ spec/fixtures/filter_range.php
29
+ spec/fixtures/filter_range_exclude.php
30
+ spec/fixtures/filter_ranges.php
31
+ spec/fixtures/filters.php
32
+ spec/fixtures/filters_different.php
33
+ spec/fixtures/geo_anchor.php
34
+ spec/fixtures/group_by_attr.php
35
+ spec/fixtures/group_by_attrpair.php
36
+ spec/fixtures/group_by_day.php
37
+ spec/fixtures/group_by_day_sort.php
38
+ spec/fixtures/group_by_month.php
39
+ spec/fixtures/group_by_week.php
40
+ spec/fixtures/group_by_year.php
41
+ spec/fixtures/group_distinct.php
42
+ spec/fixtures/id_range.php
43
+ spec/fixtures/id_range64.php
44
+ spec/fixtures/index_weights.php
45
+ spec/fixtures/keywords.php
46
+ spec/fixtures/limits.php
47
+ spec/fixtures/limits_cutoff.php
48
+ spec/fixtures/limits_max.php
49
+ spec/fixtures/limits_max_cutoff.php
50
+ spec/fixtures/match_all.php
51
+ spec/fixtures/match_any.php
52
+ spec/fixtures/match_boolean.php
53
+ spec/fixtures/match_extended.php
54
+ spec/fixtures/match_extended2.php
55
+ spec/fixtures/match_fullscan.php
56
+ spec/fixtures/match_phrase.php
57
+ spec/fixtures/max_query_time.php
58
+ spec/fixtures/miltiple_queries.php
59
+ spec/fixtures/ranking_bm25.php
60
+ spec/fixtures/ranking_none.php
61
+ spec/fixtures/ranking_proximity_bm25.php
62
+ spec/fixtures/ranking_wordcount.php
63
+ spec/fixtures/retries.php
64
+ spec/fixtures/retries_delay.php
65
+ spec/fixtures/sort_attr_asc.php
66
+ spec/fixtures/sort_attr_desc.php
67
+ spec/fixtures/sort_expr.php
68
+ spec/fixtures/sort_extended.php
69
+ spec/fixtures/sort_relevance.php
70
+ spec/fixtures/sort_time_segments.php
71
+ spec/fixtures/sphinxapi.php
72
+ spec/fixtures/update_attributes.php
73
+ spec/fixtures/weights.php
74
+ spec/sphinx/sphinx.conf
75
+ spec/sphinx/sphinx_test.sql
data/README.rdoc ADDED
@@ -0,0 +1,149 @@
1
+ = rlibsphinxclient
2
+
3
+ A Ruby wrapper for pure C searchd client API library. This is *highly experimental* library
4
+ so use it at your own risk.
5
+
6
+ == Installing the rlibsphinxclient gem
7
+
8
+ This gem can be more difficult to install than the typical Ruby extension. First you have to
9
+ install Sphinx and Sphinx pure C searchd client API library.
10
+
11
+ === Step 1: Install Sphinx and client API
12
+
13
+ Go to http://sphinxsearch.com/downloads.html and download the latest stable release.
14
+ Install it to your preferred folder (I like /opt/sphinx):
15
+
16
+ ./configure --prefix=/opt/sphinx
17
+ make
18
+ sudo make install
19
+
20
+ Then go to <tt>api/libsphinxclient</tt> directory and install client API library to the same
21
+ folder:
22
+
23
+ cd api/libsphinxclient
24
+ ./configure --prefix=/opt/sphinx
25
+ make
26
+ sudo make install
27
+
28
+ On Max OS X you may get following error:
29
+
30
+ configure: error: C++ preprocessor "/lib/cpp" fails sanity check
31
+
32
+ In this case you should specify environment variable for <tt>./configure</tt> script:
33
+
34
+ CXXCPP="gcc -E" ./configure --prefix=/opt/sphinx
35
+
36
+ === Step 2: Install rlibsphinxclient gem
37
+
38
+ If you have installed the Sphinx to <tt>/opt/sphinx</tt>, just run:
39
+
40
+ sudo gem install rlibsphinxclient --no-ri --no-rdoc
41
+
42
+ Otherwise, specify where sphinx has been installed to:
43
+
44
+ sudo gem install rlibsphinxclient --no-ri --no-rdoc -- --with-libsphinxclient-dir=/opt/sphinx-0.9.9
45
+
46
+ On Mac OS X you should specify <tt>ARCHFLAGS</tt> environment variable:
47
+
48
+ env ARCHFLAGS="-arch i386" sudo gem install rlibsphinxclient --no-rdoc --no-ri -- --with-libsphinxclient-dir=/opt/sphinx-0.9.9
49
+
50
+ == Using the rlibsphinxclient gem
51
+
52
+ The gem includes two versions of the client API: pure Ruby and wrapper for pure C client API.
53
+ They are 100% equivalent in use, so you can switch to any of them. To use pure Ruby client,
54
+ instantiate the <tt>Sphinx::Client</tt>, for pure C wrapper use <tt>Sphinx::FastClient</tt>.
55
+
56
+ Important note: you should call <tt>destroy</tt> method when you do not need client API any more.
57
+ The reason for that is the C wrapper saves all query results in memory, and frees them in
58
+ the <tt>destroy</tt> method call. You can omit this call in pure Ruby library, but I'd like
59
+ to do call in any case just for consistence (to be able to switch to another client).
60
+
61
+ Important note #2: to ensure that <tt>destroy</tt> method will be called, use <tt>ensure</tt>
62
+ block:
63
+
64
+ begin
65
+ @sphinx = Sphinx::FastClient.new
66
+ @sphinx.Query('test')
67
+ ensure
68
+ @sphinx.destroy
69
+ end
70
+
71
+ == Examples of usage
72
+
73
+ Ok, let's take a look at the examples. First, here is the search example with all possible
74
+ filters and options set:
75
+
76
+ require 'sphinx'
77
+ @sphinx = Sphinx::FastClient.new
78
+ @sphinx.SetServer('localhost', 3312)
79
+ @sphinx.SetLimits(1, 100, 20, 30)
80
+ @sphinx.SetMaxQueryTime(5)
81
+ @sphinx.SetMatchMode(Sphinx::Client::SPH_MATCH_EXTENDED2)
82
+ @sphinx.SetRankingMode(Sphinx::Client::SPH_RANK_BM25)
83
+ @sphinx.SetSortMode(Sphinx::Client::SPH_SORT_RELEVANCE)
84
+ @sphinx.SetFieldWeights('group_id' => 10, 'rating' => 20)
85
+ @sphinx.SetIndexWeights('test1' => 20, 'test2' => 30)
86
+ @sphinx.SetIDRange(1, 100)
87
+ @sphinx.SetFilter('group_id', [1], true)
88
+ @sphinx.SetFilterRange('group_id', 1, 2, true)
89
+ @sphinx.SetFilterFloatRange('rating', 1, 3, true)
90
+ @sphinx.SetGroupBy('created_at', Sphinx::Client::SPH_GROUPBY_DAY)
91
+ @sphinx.SetGroupDistinct('group_id')
92
+ @sphinx.SetRetries(5, 10)
93
+ results = @sphinx.Query('test')
94
+ @sphinx.destroy
95
+
96
+ <tt>BuildKeywords</tt> example:
97
+
98
+ require 'sphinx'
99
+ @sphinx = Sphinx::FastClient.new
100
+ results = @sphinx.BuildKeywords('wifi gprs', 'test1', true)
101
+ @sphinx.destroy
102
+
103
+ <tt>BuildExcerpts</tt> example:
104
+
105
+ require 'sphinx'
106
+ @sphinx = Sphinx::FastClient.new
107
+ results = @sphinx.BuildExcerpts(['what the world', 'London is the capital of Great Britain'], 'test1', 'the')
108
+ @sphinx.destroy
109
+
110
+ <tt>UpdateAttributes</tt> example:
111
+
112
+ require 'sphinx'
113
+ @sphinx = Sphinx::FastClient.new
114
+ results = @sphinx.UpdateAttributes('test1', ['group_id'], { 2 => [1] })
115
+ @sphinx.destroy
116
+
117
+ == Benchmarks
118
+
119
+ The reason to write this gem was to investigate why we keep getting timeout errors
120
+ when using Sphinx (occur rarely, but they are annoying me.) But the side effect of
121
+ this library was the slight search performance improvement: Ruby library is slower
122
+ when generating Sphinx request and parsing its results.
123
+
124
+ require 'sphinx'
125
+ require 'benchmark'
126
+
127
+ def run_test(klass)
128
+ sphinx = klass.new
129
+ sphinx.Query('test hello')
130
+ ensure
131
+ sphinx.destroy
132
+ end
133
+
134
+ Benchmark.bm do |x|
135
+ x.report('pure ruby') { 1000.times { run_test(Sphinx::Client) } }
136
+ x.report('c wrapper') { 1000.times { run_test(Sphinx::FastClient) } }
137
+ end
138
+
139
+ On my MBP I got the following results:
140
+
141
+ user system total real
142
+ pure ruby 0.420000 0.230000 0.650000 ( 14.721659)
143
+ c wrapper 0.060000 0.090000 0.150000 ( 2.248645)
144
+
145
+ == Who are the authors?
146
+
147
+ This plugin has been created in Scribd.com for our internal use and then the sources were opened
148
+ for other people to use. All the code in this package has been developed by Dmytro Shteflyuk
149
+ for Scribd.com and is released under the GPLv2 license. For more details, see LICENSE file.
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+ require 'spec/rake/spectask'
5
+ require 'rake/rdoctask'
6
+
7
+ Echoe.new('rlibsphinxclient') do |p|
8
+ p.author = 'Dmytro Shteflyuk'
9
+ p.email = 'kpumuk@kpumuk.info'
10
+ p.summary = 'A Ruby wrapper for pure C searchd client API library'
11
+ p.url = 'http://github.com/kpumuk/rlibsphinxclient'
12
+ p.version = '0.2.0'
13
+ end
14
+
15
+ desc 'Update SWIG wrapper for pure C searchd client API library'
16
+ task :swig do
17
+ system 'cd ext && swig -I/opt/local/include -I/opt/sphinx-0.9.9/include -ruby -autorename rlibsphinxclient.i'
18
+ end
19
+
20
+ desc 'Generate documentation for the rlibsphinxclient gem.'
21
+ Rake::RDocTask.new(:rdoc) do |rdoc|
22
+ rdoc.rdoc_dir = 'rdoc'
23
+ rdoc.title = 'rlibsphinxclient'
24
+ rdoc.options << '--line-numbers' << '--inline-source'
25
+ rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG', 'LICENSE')
26
+ rdoc.rdoc_files.include('lib/**/*.rb')
27
+ end
28
+
29
+ desc 'Builds a gem and installs it to ~/.gem folder. Used only for development purposes.'
30
+ task :dev do
31
+ system 'rake package'
32
+ system 'cd pkg && env ARCHFLAGS="-arch i386" DEBUG=1 gem install rlibsphinxclient --no-rdoc --no-ri -- --with-libsphinxclient-dir=/opt/sphinx-0.9.9'
33
+ end
data/ext/extconf.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'mkmf'
2
+
3
+ $CFLAGS.gsub! /-O\d/, ''
4
+
5
+ if ENV['DEBUG']
6
+ puts "setting debug flags"
7
+ $CFLAGS << " -O0 -ggdb -DHAVE_DEBUG"
8
+ else
9
+ $CFLAGS << " -O3"
10
+ end
11
+
12
+ find_library(*['sphinxclient', 'sphinx_create', '/opt/sphinx'].compact) or
13
+ find_library(*['sphinxclient', 'sphinx_create', dir_config('libsphinxclient').last].compact) or
14
+ raise "shared library 'libsphinxclient' not found"
15
+
16
+ find_header(*['sphinxclient.h', '/opt/sphinx'].compact) or
17
+ find_header(*['sphinxclient.h', dir_config('libsphinxclient').first].compact) or
18
+ raise "header file 'sphinxclient.h' not found"
19
+
20
+ create_makefile 'rlibsphinxclient'
@@ -0,0 +1,314 @@
1
+ %module rlibsphinxclient
2
+ %{
3
+ #include <sphinxclient.h>
4
+ %}
5
+
6
+ %include "typemaps.i"
7
+
8
+ %newobject sphinx_create;
9
+
10
+ /* -----------------------------------------------------------------------------
11
+ * This section contains generic input parameter type mappings.
12
+ * ----------------------------------------------------------------------------- */
13
+
14
+ // Processing (sphinx_bool) params
15
+ %typemap(in) sphinx_bool {
16
+ switch(TYPE($input)) {
17
+ case T_TRUE:
18
+ case T_FALSE:
19
+ $1 = $input == Qtrue ? SPH_TRUE : SPH_FALSE;
20
+ break;
21
+ default:
22
+ SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument " "$argnum"" of type '" "$1_type""'");
23
+ break;
24
+ }
25
+ }
26
+
27
+ // Processing (sphinx_uint64_t *) params.
28
+ %typemap(in) sphinx_uint64_t * {
29
+ int size = RARRAY_LEN($input), i;
30
+
31
+ $1 = (sphinx_uint64_t *) malloc(size * sizeof(sphinx_uint64_t));
32
+ VALUE *ptr = RARRAY_PTR($input);
33
+ for (i = 0; i < size; i++, ptr++) {
34
+ $1[i] = NUM2ULL(*ptr);
35
+ }
36
+ }
37
+
38
+ // Cleaning up (sphinx_uint64_t *) params.
39
+ %typemap(freearg) sphinx_uint64_t * {
40
+ free((char *) $1);
41
+ }
42
+
43
+ // Processing (int *) params.
44
+ %typemap(in) int * {
45
+ int size = RARRAY_LEN($input), i;
46
+
47
+ $1 = (int *) malloc(size * sizeof(int));
48
+ VALUE *ptr = RARRAY_PTR($input);
49
+ for (i = 0; i < size; i++, ptr++) {
50
+ $1[i] = NUM2INT(*ptr);
51
+ }
52
+ }
53
+
54
+ // Cleaning up (int *) params.
55
+ %typemap(freearg) int * {
56
+ free((char *) $1);
57
+ }
58
+
59
+ // Processing (char **) params.
60
+ %typemap(in) char ** {
61
+ int size = RARRAY_LEN($input), i;
62
+
63
+ $1 = (char **) malloc(size * sizeof(char *));
64
+ VALUE *ptr = RARRAY_PTR($input);
65
+ for (i = 0; i < size; i++, ptr++) {
66
+ $1[i] = STR2CSTR(*ptr);
67
+ }
68
+ }
69
+
70
+ // Cleaning up (char **) params.
71
+ %typemap(freearg) char ** {
72
+ free((char *) $1);
73
+ }
74
+
75
+ /* -----------------------------------------------------------------------------
76
+ * This section contains sphinx_result return value type mappings
77
+ * (functions sphinx_query and sphinx_run_queries.)
78
+ * ----------------------------------------------------------------------------- */
79
+
80
+ // Processing sphinx_run_queries return value (array of sphinx_result).
81
+ %typemap(out) (sphinx_result *) {
82
+ int num_results = sphinx_get_num_results(arg1), i;
83
+
84
+ $result = rb_ary_new();
85
+ for (i = 0; i < num_results; i++) {
86
+ rb_ary_store($result, i, convert_sphinx_result(arg1, $1 + i));
87
+ }
88
+ }
89
+ sphinx_result * sphinx_run_queries(sphinx_client * client);
90
+
91
+ // Processing sphinx_query return value (single instance of sphinx_result).
92
+ %typemap(out) (sphinx_result *) {
93
+ $result = convert_sphinx_result(arg1, $1);
94
+ }
95
+
96
+ /* -----------------------------------------------------------------------------
97
+ * This section contains type mappings for sphinx_build_excerpts function.
98
+ * ----------------------------------------------------------------------------- */
99
+
100
+ // Processing sphinx_excerpt_options input parameter.
101
+ %typemap(in) sphinx_excerpt_options * (sphinx_excerpt_options opts, VALUE val) {
102
+ Check_Type($input, T_HASH);
103
+ sphinx_init_excerpt_options(&opts);
104
+
105
+ // before_match
106
+ val = rb_hash_aref($input, rb_str_new2("before_match"));
107
+ if (val != Qnil) {
108
+ Check_Type($input, T_STRING);
109
+ opts.before_match = STR2CSTR(val);
110
+ }
111
+
112
+ // after_match
113
+ val = rb_hash_aref($input, rb_str_new2("after_match"));
114
+ if (val != Qnil) {
115
+ Check_Type($input, T_STRING);
116
+ opts.after_match = STR2CSTR(val);
117
+ }
118
+
119
+ // chunk_separator
120
+ val = rb_hash_aref($input, rb_str_new2("chunk_separator"));
121
+ if (val != Qnil) {
122
+ Check_Type($input, T_STRING);
123
+ opts.chunk_separator = STR2CSTR(val);
124
+ }
125
+
126
+ // limit
127
+ val = rb_hash_aref($input, rb_str_new2("limit"));
128
+ if (val != Qnil) {
129
+ Check_Type($input, T_FIXNUM);
130
+ opts.limit = NUM2INT(val);
131
+ }
132
+
133
+ // around
134
+ val = rb_hash_aref($input, rb_str_new2("around"));
135
+ if (val != Qnil) {
136
+ Check_Type($input, T_FIXNUM);
137
+ opts.around = NUM2INT(val);
138
+ }
139
+
140
+ // exact_phrase
141
+ val = rb_hash_aref($input, rb_str_new2("exact_phrase"));
142
+ if (val != Qnil) {
143
+ opts.around = val == Qtrue ? SPH_TRUE : SPH_FALSE;
144
+ }
145
+
146
+ // single_passage
147
+ val = rb_hash_aref($input, rb_str_new2("single_passage"));
148
+ if (val != Qnil) {
149
+ opts.single_passage = val == Qtrue ? SPH_TRUE : SPH_FALSE;
150
+ }
151
+
152
+ // use_boundaries
153
+ val = rb_hash_aref($input, rb_str_new2("use_boundaries"));
154
+ if (val != Qnil) {
155
+ opts.use_boundaries = val == Qtrue ? SPH_TRUE : SPH_FALSE;
156
+ }
157
+
158
+ // weight_order
159
+ val = rb_hash_aref($input, rb_str_new2("weight_order"));
160
+ if (val != Qnil) {
161
+ opts.weight_order = val == Qtrue ? SPH_TRUE : SPH_FALSE;
162
+ }
163
+
164
+ $1 = &opts;
165
+ }
166
+
167
+ // Processing char ** output parameter.
168
+ %typemap(out) char ** {
169
+ int num_docs, i;
170
+
171
+ SWIG_AsVal_int(argv[1], &num_docs);
172
+
173
+ if ($1) {
174
+ $result = rb_ary_new();
175
+ for (i = 0; i < num_docs; i++) {
176
+ rb_ary_store($result, i, rb_str_new2($1[i]));
177
+
178
+ free((char *) $1[i]);
179
+ }
180
+ free((char *) $1);
181
+ } else {
182
+ $result = Qfalse;
183
+ }
184
+ }
185
+ char ** sphinx_build_excerpts(sphinx_client * client, int num_docs, const char ** docs, const char * index, const char * words, sphinx_excerpt_options * opts);
186
+ %typemap(in) sphinx_excerpt_options * {}
187
+ %typemap(out) char ** {}
188
+
189
+ /* -----------------------------------------------------------------------------
190
+ * This section contains type mappings for sphinx_build_keywords function.
191
+ * ----------------------------------------------------------------------------- */
192
+
193
+ // Defining out_num_keywords input parameter (will contain a number of keywords).
194
+ %typemap(in, numinputs = 0) int * out_num_keywords (int out_num_keywords) {
195
+ $1 = &out_num_keywords;
196
+ }
197
+
198
+ // Doing nothing because out_num_keywords is a local variable.
199
+ %typemap(freearg) int * out_num_keywords {
200
+ }
201
+
202
+ // Processing array of sphinx_keyword_info values.
203
+ %typemap(out) sphinx_keyword_info * {
204
+ int i;
205
+ VALUE keyword = Qnil;
206
+ $result = rb_ary_new();
207
+ for (i = 0; i < out_num_keywords5; i++) {
208
+ keyword = rb_hash_new();
209
+ rb_hash_aset(keyword, rb_str_new2("tokenized"), rb_str_new2($1[i].tokenized));
210
+ rb_hash_aset(keyword, rb_str_new2("normalized"), rb_str_new2($1[i].normalized));
211
+ rb_hash_aset(keyword, rb_str_new2("docs"), INT2FIX($1[i].num_docs));
212
+ rb_hash_aset(keyword, rb_str_new2("hits"), INT2FIX($1[i].num_hits));
213
+ rb_ary_store($result, i, keyword);
214
+
215
+ free((char *) $1[i].tokenized);
216
+ free((char *) $1[i].normalized);
217
+ }
218
+
219
+ free((char *) $1);
220
+ }
221
+
222
+ /* -----------------------------------------------------------------------------
223
+ * This section contains some useful helpers for type mappers.
224
+ * ----------------------------------------------------------------------------- */
225
+
226
+ %{
227
+ static VALUE convert_sphinx_result(sphinx_client *client, sphinx_result *input) {
228
+ int i, j, k;
229
+ VALUE result = Qnil, var1 = Qnil, var2 = Qnil, var3 = Qnil, var4 = Qnil;
230
+ char *msg = (char *) 0;
231
+ unsigned int *mva = 0;
232
+ char *time = 0;
233
+
234
+ if (!input) {
235
+ result = Qfalse;
236
+ } else {
237
+ result = rb_hash_new();
238
+ rb_hash_aset(result, rb_str_new2("error"), input->error ? rb_str_new2(input->error) : Qnil);
239
+ rb_hash_aset(result, rb_str_new2("warning"), input->warning ? rb_str_new2(input->warning) : Qnil);
240
+ rb_hash_aset(result, rb_str_new2("status"), INT2FIX(input->status));
241
+ if (input->status != SEARCHD_OK && input->status != SEARCHD_WARNING) {
242
+ return result;
243
+ }
244
+
245
+ rb_hash_aset(result, rb_str_new2("total"), INT2FIX(input->total));
246
+ rb_hash_aset(result, rb_str_new2("total_found"), INT2FIX(input->total_found));
247
+ time = (char *) malloc(20);
248
+ sprintf(time, "%.3f", input->time_msec / 1000.);
249
+ rb_hash_aset(result, rb_str_new2("time"), rb_str_new2(time));
250
+ free(time);
251
+
252
+ // fields
253
+ var1 = rb_ary_new();
254
+ for (i = 0; i < input->num_fields; i++) {
255
+ rb_ary_store(var1, i, rb_str_new2(input->fields[i]));
256
+ }
257
+ rb_hash_aset(result, rb_str_new2("fields"), var1);
258
+
259
+ // attrs
260
+ var1 = rb_hash_new();
261
+ for (i = 0; i < input->num_attrs; i++) {
262
+ rb_hash_aset(var1, rb_str_new2(input->attr_names[i]), INT2NUM(input->attr_types[i]));
263
+ }
264
+ rb_hash_aset(result, rb_str_new2("attrs"), var1);
265
+
266
+ // words
267
+ var1 = rb_hash_new();
268
+ for (i = 0; i < input->num_words; i++) {
269
+ var2 = rb_hash_new();
270
+ rb_hash_aset(var2, rb_str_new2("docs"), INT2FIX(input->words[i].docs));
271
+ rb_hash_aset(var2, rb_str_new2("hits"), INT2FIX(input->words[i].hits));
272
+
273
+ rb_hash_aset(var1, rb_str_new2(input->words[i].word), var2);
274
+ }
275
+ rb_hash_aset(result, rb_str_new2("words"), var1);
276
+
277
+ // matches
278
+ var1 = rb_ary_new();
279
+ for (i = 0; i < input->num_matches; i++) {
280
+ var2 = rb_hash_new();
281
+ rb_hash_aset(var2, rb_str_new2("id"), ULL2NUM(sphinx_get_id(input, i)));
282
+ rb_hash_aset(var2, rb_str_new2("weight"), INT2FIX(sphinx_get_weight(input, i)));
283
+
284
+ var3 = rb_hash_new();
285
+ for (j = 0; j < input->num_attrs; j++) {
286
+ switch (input->attr_types[j]) {
287
+ case SPH_ATTR_MULTI | SPH_ATTR_INTEGER:
288
+ mva = (unsigned int *) sphinx_get_mva(input, i, j);
289
+ var4 = rb_ary_new();
290
+ for (k = 0; k < (int) mva[0]; k++) {
291
+ rb_ary_store(var4, k, INT2NUM(mva[k + 1]));
292
+ }
293
+ break;
294
+ case SPH_ATTR_FLOAT:
295
+ var4 = rb_float_new(sphinx_get_float(input, i, j));
296
+ break;
297
+ default:
298
+ var4 = ULL2NUM(sphinx_get_int(input, i, j));
299
+ break;
300
+ }
301
+ rb_hash_aset(var3, rb_str_new2(input->attr_names[j]), var4);
302
+ }
303
+ rb_hash_aset(var2, rb_str_new2("attrs"), var3);
304
+
305
+ rb_ary_store(var1, i, var2);
306
+ }
307
+ rb_hash_aset(result, rb_str_new2("matches"), var1);
308
+ }
309
+
310
+ return result;
311
+ }
312
+ %}
313
+
314
+ %include "/opt/sphinx-0.9.9/include/sphinxclient.h"