groonga 0.0.6 → 0.0.7

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 (55) hide show
  1. data/AUTHORS +4 -0
  2. data/NEWS.ja.rdoc +10 -0
  3. data/NEWS.rdoc +10 -0
  4. data/README.ja.rdoc +9 -3
  5. data/README.rdoc +10 -4
  6. data/Rakefile +1 -1
  7. data/TUTORIAL.ja.rdoc +3 -6
  8. data/example/bookmark.rb +1 -1
  9. data/example/search/config.ru +52 -28
  10. data/ext/rb-grn-column.c +24 -18
  11. data/ext/rb-grn-context.c +165 -17
  12. data/ext/rb-grn-encoding.c +37 -0
  13. data/ext/rb-grn-expression.c +286 -51
  14. data/ext/rb-grn-object.c +27 -8
  15. data/ext/rb-grn-operation.c +128 -22
  16. data/ext/rb-grn-patricia-trie.c +62 -0
  17. data/ext/rb-grn-snippet.c +7 -17
  18. data/ext/rb-grn-table.c +101 -31
  19. data/ext/rb-grn-utils.c +87 -22
  20. data/ext/rb-grn-variable-size-column.c +1 -1
  21. data/ext/rb-grn.h +27 -4
  22. data/ext/rb-groonga.c +12 -2
  23. data/extconf.rb +2 -1
  24. data/html/index.html +2 -2
  25. data/lib/groonga.rb +1 -0
  26. data/lib/groonga/expression-builder.rb +47 -12
  27. data/lib/groonga/patricia-trie.rb +40 -0
  28. data/lib/groonga/record.rb +17 -13
  29. data/misc/grnop2ruby.rb +49 -0
  30. data/pkg-config.rb +1 -1
  31. data/test-unit/lib/test/unit/assertions.rb +5 -2
  32. data/test-unit/lib/test/unit/autorunner.rb +19 -4
  33. data/test-unit/lib/test/unit/collector/load.rb +3 -1
  34. data/test-unit/lib/test/unit/color-scheme.rb +5 -1
  35. data/test-unit/lib/test/unit/error.rb +7 -5
  36. data/test-unit/lib/test/unit/runner/tap.rb +8 -0
  37. data/test-unit/lib/test/unit/ui/console/testrunner.rb +63 -8
  38. data/test-unit/lib/test/unit/ui/tap/testrunner.rb +92 -0
  39. data/test-unit/test/collector/test-load.rb +1 -5
  40. data/test-unit/test/test-color-scheme.rb +4 -0
  41. data/test/groonga-test-utils.rb +10 -0
  42. data/test/run-test.rb +5 -1
  43. data/test/test-column.rb +58 -0
  44. data/test/test-database.rb +8 -1
  45. data/test/test-expression.rb +48 -6
  46. data/test/test-hash.rb +7 -0
  47. data/test/test-patricia-trie.rb +39 -0
  48. data/test/test-record.rb +2 -2
  49. data/test/test-remote.rb +52 -0
  50. data/test/test-schema.rb +1 -1
  51. data/test/test-table-select-normalize.rb +48 -0
  52. data/test/test-table-select.rb +101 -0
  53. data/test/test-table.rb +0 -9
  54. data/test/test-variable-size-column.rb +28 -0
  55. metadata +16 -5
data/AUTHORS CHANGED
@@ -1 +1,5 @@
1
1
  Kouhei Sutou <kou@clear-code.com>
2
+ Tasuku SUENAGA <a@razil.jp>
3
+ daijiro <morita@razil.jp>
4
+ Yuto HAYAMIZU <y.hayamizu@gmail.com>
5
+ SHIDARA Yoji <dara@shidara.net>
@@ -1,5 +1,15 @@
1
1
  = お知らせ
2
2
 
3
+ == 0.0.7: 2009-10-02
4
+
5
+ * groonga 0.1.4対応
6
+ * APIの追加
7
+ * Groonga::PatriciaTrie#scan
8
+ * Groonga::PatriciaTrie#tag_keys
9
+ * Groonga::Expression#snippet
10
+ * Groonga::Object#append
11
+ * Groonga::Object#prepend
12
+
3
13
  == 0.0.6: 2009-07-31
4
14
 
5
15
  * groonga 0.1.1対応
data/NEWS.rdoc CHANGED
@@ -1,5 +1,15 @@
1
1
  = NEWS
2
2
 
3
+ == 0.0.7: 2009-10-02
4
+
5
+ * Supported groonga 0.1.4
6
+ * Added API
7
+ * Groonga::PatriciaTrie#scan
8
+ * Groonga::PatriciaTrie#tag_keys
9
+ * Groonga::Expression#snippet
10
+ * Groonga::Object#append
11
+ * Groonga::Object#prepend
12
+
3
13
  == 0.0.6: 2009-07-31
4
14
 
5
15
  * Supported groonga 0.1.1.
@@ -20,7 +20,11 @@ groongaに関する情報は以下を参照して下さい。
20
20
 
21
21
  == 作者
22
22
 
23
- Kouhei Sutou: <tt><kou@clear-code.com></tt>
23
+ Kouhei Sutou:: <tt><kou@clear-code.com></tt>
24
+ Tasuku SUENAGA:: <tt><a@razil.jp></tt>
25
+ daijiro:: <tt><morita@razil.jp></tt>
26
+ Yuto HAYAMIZU:: <tt><y.hayamizu@gmail.com></tt>
27
+ SHIDARA Yoji:: <tt><dara@shidara.net></tt>
24
28
 
25
29
  == ライセンス
26
30
 
@@ -32,7 +36,7 @@ pkg-config.rbはrcairoに付属しているもので、これはRubyライセ
32
36
  == 依存ソフトウェア
33
37
 
34
38
  * Ruby >= 1.8 (1.9.1対応)
35
- * groonga >= 0.1.1
39
+ * groonga >= 0.1.4
36
40
 
37
41
  == インストール
38
42
 
@@ -53,5 +57,7 @@ http://lists.sourceforge.jp/mailman/listinfo/groonga-dev
53
57
  * 森さん: 最新groonga対応パッチをくれました。
54
58
  * グニャラくん: バグレポートしてくれました。
55
59
  * にくさん: バグレポートしてくれました。
56
- * daraさん: テストを書いてくれました。
60
+ * daraさん:
61
+ * テストを書いてくれました。
62
+ * バグを直してくれました。
57
63
  * id:mat_akiさん: チュートリアルのバグを教えてくれました。
@@ -18,9 +18,13 @@ See the following URL about groonga.
18
18
 
19
19
  * groonga: http://groonga.org/
20
20
 
21
- == Author
21
+ == Authors
22
22
 
23
- Kouhei Sutou: <tt><kou@clear-code.com></tt>
23
+ Kouhei Sutou:: <tt><kou@clear-code.com></tt>
24
+ Tasuku SUENAGA:: <tt><a@razil.jp></tt>
25
+ daijiro:: <tt><morita@razil.jp></tt>
26
+ Yuto HAYAMIZU:: <tt><y.hayamizu@gmail.com></tt>
27
+ SHIDARA Yoji:: <tt><dara@shidara.net></tt>
24
28
 
25
29
  == License
26
30
 
@@ -33,7 +37,7 @@ license/GPL for details.
33
37
  == Dependencies
34
38
 
35
39
  * Ruby >= 1.8 (including 1.9.1)
36
- * groonga >= 0.1.1
40
+ * groonga >= 0.1.4
37
41
 
38
42
  == Install
39
43
 
@@ -54,5 +58,7 @@ http://rubyforge.org/mailman/listinfo/groonga-users-en
54
58
  * mori: sent patches to support the latest groonga.
55
59
  * Tasuku SUENAGA: sent bug reports.
56
60
  * niku: sent bug reports.
57
- * dara: wrote tests.
61
+ * dara:
62
+ * wrote tests.
63
+ * fixed bugs.
58
64
  * id:mat_aki: sent bug reports.
data/Rakefile CHANGED
@@ -54,7 +54,7 @@ base_dir_included_components = %w(AUTHORS Rakefile
54
54
  TUTORIAL.ja.rdoc
55
55
  extconf.rb pkg-config.rb)
56
56
  excluded_components = %w(.cvsignore .gdb_history CVS depend Makefile pkg
57
- .svn .git doc vendor .test-result)
57
+ .svn .git doc vendor data .test-result)
58
58
  excluded_suffixes = %w(.png .ps .pdf .o .so .a .txt .~)
59
59
  Find.find(base_dir) do |target|
60
60
  target = truncate_base_dir[target]
@@ -53,7 +53,7 @@ groongaには以下の3種類のテーブルがあります。
53
53
  ここではハッシュテーブルを利用して、<tt><items></tt>という名前のテー
54
54
  ブルを作成します。
55
55
 
56
- >> items = Groonga::Hash.create(:name => "<items>", :persistent => true)
56
+ >> items = Groonga::Hash.create(:name => "<items>")
57
57
  => #<Groonga::Hash ...>
58
58
 
59
59
 
@@ -93,7 +93,7 @@ groongaには以下の3種類のテーブルがあります。
93
93
 
94
94
  まず<tt><items></tt>テーブルに+title+という名前のカラムを追加します。
95
95
 
96
- >> title_column = items.define_column("title", "<text>", :persistent => true)
96
+ >> title_column = items.define_column("title", "<text>")
97
97
  => #<Groonga::VarSizeColumn ...>
98
98
 
99
99
  2番目の引数は、追加するカラムのデータ型を示しています。
@@ -106,7 +106,6 @@ groongaには以下の3種類のテーブルがあります。
106
106
 
107
107
  >> terms = Groonga::Hash.create(:name => "<terms>",
108
108
  :key_type => "<shorttext>",
109
- :persistent => true,
110
109
  :default_tokenizer => "<token:bigram>")
111
110
  => #<Groonga::Hash ...>
112
111
 
@@ -126,7 +125,6 @@ N-gramを利用した全文検索では、分解したN文字とその出現位
126
125
  ルの+title+カラムに対するインデックスを定義します。
127
126
 
128
127
  >> title_index_column = terms.define_index_column("item_title", items,
129
- :persistent => true,
130
128
  :source => "<items>.title")
131
129
  => #<Groonga::IndexColumn ...>
132
130
 
@@ -187,8 +185,7 @@ http://qwik.jp/senna/senna2.files/rect4605.png
187
185
 
188
186
  次に、<tt><comments></tt>テーブルを追加します。
189
187
 
190
- >> comments = Groonga::Array.create(:name => "<comments>",
191
- :key_type => "<shorttext>")
188
+ >> comments = Groonga::Array.create(:name => "<comments>")
192
189
  => #<Groonga::Array ...>
193
190
  >> comments.define_column("item", items)
194
191
  => #<Groonga::FixSizeColumn ..>
@@ -107,7 +107,7 @@ p add_bookmark("http://d.hatena.ne.jp/higepon/20070815/1187192864",
107
107
  "末尾再帰", "taporobo", "末尾再帰 Scheme LISP", 1187568793)
108
108
  p add_bookmark("http://practical-scheme.net/docs/cont-j.html",
109
109
  "なんでも継続", "taporobo", "トランポリン LISP continuation",
110
- 1187568692)
110
+ 1187568692.98765)
111
111
  p add_bookmark("http://jp.rubyist.net/managinze",
112
112
  "るびま", "moritan", "Ruby ドキュメント",
113
113
  Time.now)
@@ -71,8 +71,8 @@ EOF
71
71
  request['query'] || ''
72
72
  end
73
73
 
74
- def words(request)
75
- query(request).split
74
+ def page(request)
75
+ (request['page'] || 0).to_i
76
76
  end
77
77
 
78
78
  def render_search_box(request, response)
@@ -88,8 +88,10 @@ EOF
88
88
  end
89
89
 
90
90
  def render_search_result(request, response)
91
- _words = words(request)
92
- if _words.empty?
91
+ _query = query(request)
92
+ _page = page(request)
93
+ limit = 20
94
+ if _query.empty?
93
95
  records = []
94
96
  response.write(<<-EOS)
95
97
  <div class='search-summary'>
@@ -97,25 +99,16 @@ EOF
97
99
  </div>
98
100
  EOS
99
101
  else
100
- offset = 0
101
102
  options = {}
102
103
  before = Time.now
103
104
  records = @documents.select do |record|
104
- expression = nil
105
- _words.each do |word|
106
- sub_expression = record["content"] =~ word
107
- if expression.nil?
108
- expression = sub_expression
109
- else
110
- expression &= sub_expression
111
- end
112
- end
113
- expression
105
+ record["content"].match(_query)
114
106
  end
115
107
  total_records = records.size
116
108
  records = records.sort([[".:score", "descending"],
117
109
  [".last-modified", "descending"]],
118
- :limit => 20)
110
+ :offset => _page * limit,
111
+ :limit => limit)
119
112
  elapsed = Time.now - before
120
113
 
121
114
  response.write(<<-EOS)
@@ -124,9 +117,9 @@ EOS
124
117
  <span class="keyword">#{escape_html(query(request))}</span>の検索結果:
125
118
  <span class="total-entries">#{total_records}</span>件中
126
119
  <span class="display-range">
127
- #{total_records.zero? ? 0 : offset + 1}
120
+ #{total_records.zero? ? 0 : _page + 1}
128
121
  -
129
- #{offset + records.size}
122
+ #{_page + records.size}
130
123
  </span>
131
124
  件(#{elapsed}秒)
132
125
  </p>
@@ -139,6 +132,8 @@ EOS
139
132
  render_record(request, response, record)
140
133
  end
141
134
  response.write(" </div>\n")
135
+
136
+ # render_pagination(request, response, _page, limit)
142
137
  end
143
138
 
144
139
  def render_record(request, response, record)
@@ -160,16 +155,11 @@ EOM
160
155
  end
161
156
 
162
157
  def render_snippet(request, response, record)
163
- open_tag = "<span class=\"keyword\">"
164
- close_tag = "</span>"
165
- snippet = Groonga::Snippet.new(:width => 100,
166
- :default_open_tag => open_tag,
167
- :default_close_tag => close_tag,
168
- :html_escape => true,
169
- :normalize => true)
170
- words(request).each do |word|
171
- snippet.add_keyword(word)
172
- end
158
+ expression = record.table.expression
159
+ snippet = expression.snippet([["<span class=\"keyword\">", "</span>"]],
160
+ :width => 100,
161
+ :html_escape => true,
162
+ :normalize => true)
173
163
  separator = "\n<span class='separator'>...</span>\n"
174
164
  response.write(<<-EOS)
175
165
  <p class="snippet">
@@ -177,6 +167,40 @@ EOM
177
167
  </p>
178
168
  EOS
179
169
  end
170
+
171
+ def render_pagination(request, response, page, limit)
172
+ _query = query(request)
173
+ return if _query.empty?
174
+
175
+ total_records = @documents.size
176
+ return if total_records < limit
177
+
178
+ last_page = total_records / limit
179
+ response.write("<div class='pagination'>\n")
180
+ if page > 0
181
+ render_pagination_link(request, response, _query, page - 1, "<<")
182
+ end
183
+ last_page.times do |i|
184
+ if i == page
185
+ response.write(pagination_span(escape_html(i)))
186
+ else
187
+ render_pagination_link(request, response, _query, i, i)
188
+ end
189
+ end
190
+ if page < last_page
191
+ render_pagination_link(request, response, _query, page + 1, ">>")
192
+ end
193
+ response.write("</div>\n")
194
+ end
195
+
196
+ def render_pagination_link(request, response, query, page, label)
197
+ href = "./?query=#{escape_html(query)};page=#{escape_html(page)}"
198
+ response.write(pagination_span("<a href='#{href}'>#{label}</a>"))
199
+ end
200
+
201
+ def pagination_span(content)
202
+ "<span class='pagination-link'>#{content}</span>\n"
203
+ end
180
204
  end
181
205
 
182
206
  run Searcher.new
@@ -167,33 +167,37 @@ rb_grn_column_select (int argc, VALUE *argv, VALUE self)
167
167
  grn_ctx *context;
168
168
  grn_obj *table, *column, *result, *expression;
169
169
  grn_operator operator = GRN_OP_OR;
170
- grn_rc rc;
171
170
  VALUE options;
172
- VALUE rb_query, rb_name, rb_operator, rb_result;
173
- char *name = NULL, *query;
174
- unsigned name_size = 0, query_size;
171
+ VALUE rb_query, rb_query_or_options, rb_name, rb_operator, rb_result;
172
+ VALUE builder;
173
+ VALUE rb_expression;
174
+
175
+ rb_query = Qnil;
175
176
 
176
- rb_scan_args(argc, argv, "11", &rb_query, &options);
177
-
178
- query = StringValueCStr(rb_query);
179
- query_size = RSTRING_LEN(rb_query);
177
+ rb_scan_args(argc, argv, "02", &rb_query_or_options, &options);
180
178
 
181
179
  rb_grn_column_deconstruct(SELF(self), &column, &context,
182
180
  NULL, NULL,
183
181
  NULL, NULL, NULL);
184
182
  table = grn_column_table(context, column);
185
183
 
184
+ if (RVAL2CBOOL(rb_obj_is_kind_of(rb_query_or_options, rb_cString))) {
185
+ rb_query = rb_query_or_options;
186
+ } else {
187
+ if (!NIL_P(options))
188
+ rb_raise(rb_eArgError,
189
+ "should be [query_string, option_hash] "
190
+ "or [option_hash]: %s",
191
+ rb_grn_inspect(rb_ary_new4(argc, argv)));
192
+ options = rb_query_or_options;
193
+ }
194
+
186
195
  rb_grn_scan_options(options,
187
196
  "operator", &rb_operator,
188
197
  "result", &rb_result,
189
198
  "name", &rb_name,
190
199
  NULL);
191
200
 
192
- if (!NIL_P(rb_name)) {
193
- name = StringValueCStr(rb_name);
194
- name_size = RSTRING_LEN(rb_name);
195
- }
196
-
197
201
  if (!NIL_P(rb_operator))
198
202
  operator = NUM2INT(rb_operator);
199
203
 
@@ -207,12 +211,14 @@ rb_grn_column_select (int argc, VALUE *argv, VALUE self)
207
211
  result = RVAL2GRNTABLE(rb_result, &context);
208
212
  }
209
213
 
210
- expression = grn_expr_create_from_str(context, name, name_size,
211
- query, query_size,
212
- table, column);
213
- rc = grn_table_select(context, table, expression, result, operator);
214
+ builder = rb_grn_column_expression_builder_new(self, rb_name, rb_query);
215
+ rb_expression = rb_grn_column_expression_builder_build(builder);
216
+ rb_grn_object_deconstruct(RB_GRN_OBJECT(DATA_PTR(rb_expression)),
217
+ &expression, NULL,
218
+ NULL, NULL, NULL, NULL);
219
+
220
+ grn_table_select(context, table, expression, result, operator);
214
221
  rb_grn_context_check(context, self);
215
- rb_grn_rc_check(rc, self);
216
222
 
217
223
  return rb_result;
218
224
  }
@@ -53,7 +53,23 @@ rb_grn_context_from_ruby_object (VALUE object)
53
53
  Data_Get_Struct(object, RbGrnContext, rb_grn_context);
54
54
  if (!rb_grn_context)
55
55
  rb_raise(rb_eGrnError, "groonga context is NULL");
56
- return &(rb_grn_context->context);
56
+ return rb_grn_context->context;
57
+ }
58
+
59
+ void
60
+ rb_grn_context_fin (grn_ctx *context)
61
+ {
62
+ grn_obj *database;
63
+
64
+ if (context->stat == GRN_CTX_FIN)
65
+ return;
66
+
67
+ database = grn_ctx_db(context);
68
+ debug("context:database: %p:%p\n", context, database);
69
+ if (database && database->header.type == GRN_DB) {
70
+ grn_obj_close(context, database);
71
+ }
72
+ grn_ctx_fin(context);
57
73
  }
58
74
 
59
75
  static void
@@ -62,22 +78,12 @@ rb_grn_context_free (void *pointer)
62
78
  RbGrnContext *rb_grn_context = pointer;
63
79
  grn_ctx *context;
64
80
 
65
- context = &(rb_grn_context->context);
81
+ context = rb_grn_context->context;
66
82
  debug("context-free: %p\n", context);
67
- if (context->stat != GRN_CTX_FIN) {
68
- grn_obj *database;
69
-
70
- database = grn_ctx_db(context);
71
- debug("context:database: %p:%p\n", context, database);
72
- if (database && database->header.type == GRN_DB) {
73
- grn_obj_close(context, database);
74
- }
75
- grn_ctx_fin(context);
76
- }
83
+ if (!rb_grn_exited)
84
+ rb_grn_context_fin(context);
77
85
  debug("context-free: %p: done\n", context);
78
86
  xfree(rb_grn_context);
79
-
80
- GRN_CTX_USER_DATA(context)->ptr = NULL;
81
87
  }
82
88
 
83
89
  static VALUE
@@ -142,6 +148,34 @@ rb_grn_context_ensure (VALUE *context)
142
148
  return SELF(*context);
143
149
  }
144
150
 
151
+ VALUE
152
+ rb_grn_context_rb_string_new (grn_ctx *context, const char *string, long length)
153
+ {
154
+ if (length < 0)
155
+ length = strlen(string);
156
+ #ifdef HAVE_RUBY_ENCODING_H
157
+ return rb_enc_str_new(string, length,
158
+ rb_grn_encoding_to_ruby_encoding(context->encoding));
159
+ #else
160
+ return rb_str_new(string, length);
161
+ #endif
162
+ }
163
+
164
+ VALUE
165
+ rb_grn_context_rb_string_encode (grn_ctx *context, VALUE rb_string)
166
+ {
167
+ #ifdef HAVE_RUBY_ENCODING_H
168
+ rb_encoding *encoding, *to_encode;
169
+
170
+ encoding = rb_enc_get(rb_string);
171
+ to_encode = rb_grn_encoding_to_ruby_encoding(context->encoding);
172
+ if (rb_enc_to_index(encoding) != rb_enc_to_index(to_encode))
173
+ rb_string = rb_str_encode(rb_string, rb_enc_from_encoding(to_encode),
174
+ 0, Qnil);
175
+ #endif
176
+ return rb_string;
177
+ }
178
+
145
179
  /*
146
180
  * call-seq:
147
181
  * Groonga::Context.default -> Groonga::Context
@@ -233,7 +267,6 @@ rb_grn_context_initialize (int argc, VALUE *argv, VALUE self)
233
267
  RbGrnContext *rb_grn_context;
234
268
  grn_ctx *context;
235
269
  int flags = 0;
236
- grn_rc rc;
237
270
  VALUE options, default_options;
238
271
  VALUE rb_encoding;
239
272
 
@@ -252,8 +285,7 @@ rb_grn_context_initialize (int argc, VALUE *argv, VALUE self)
252
285
 
253
286
  rb_grn_context = ALLOC(RbGrnContext);
254
287
  DATA_PTR(self) = rb_grn_context;
255
- context = &(rb_grn_context->context);
256
- rc = grn_ctx_init(context, flags);
288
+ context = rb_grn_context->context = grn_ctx_open(flags);
257
289
  rb_grn_context_check(context, self);
258
290
 
259
291
  GRN_CTX_USER_DATA(context)->ptr = rb_grn_context;
@@ -351,6 +383,108 @@ rb_grn_context_get_database (VALUE self)
351
383
  return GRNDB2RVAL(context, grn_ctx_db(context), RB_GRN_FALSE);
352
384
  }
353
385
 
386
+ /*
387
+ * call-seq:
388
+ * context.connect(options=nil)
389
+ *
390
+ * groongaサーバに接続する。_options_に指定可能な値は以下の通
391
+ * り。
392
+ *
393
+ * [+:host+]
394
+ * groongaサーバのホスト名。またはIPアドレス。省略すると
395
+ * "localhost"に接続する。
396
+ *
397
+ * [+:port+]
398
+ * groongaサーバのポート番号。省略すると10041番ポートに接
399
+ * 続する。
400
+ */
401
+ static VALUE
402
+ rb_grn_context_connect (int argc, VALUE *argv, VALUE self)
403
+ {
404
+ grn_ctx *context;
405
+ char *host;
406
+ int port;
407
+ int flags = 0;
408
+ grn_rc rc;
409
+ VALUE options, rb_host, rb_port;
410
+
411
+ rb_scan_args(argc, argv, "01", &options);
412
+ rb_grn_scan_options(options,
413
+ "host", &rb_host,
414
+ "port", &rb_port,
415
+ NULL);
416
+
417
+ context = SELF(self);
418
+
419
+ if (NIL_P(rb_host)) {
420
+ host = "localhost";
421
+ } else {
422
+ host = StringValueCStr(rb_host);
423
+ }
424
+
425
+ if (NIL_P(rb_port)) {
426
+ port = 10041;
427
+ } else {
428
+ port = NUM2INT(rb_port);
429
+ }
430
+
431
+ rc = grn_ctx_connect(context, host, port, flags);
432
+ rb_grn_context_check(context, self);
433
+ rb_grn_rc_check(rc, self);
434
+
435
+ return Qnil;
436
+ }
437
+
438
+ /*
439
+ * call-seq:
440
+ * context.send(string) -> ID
441
+ *
442
+ * groongaサーバにクエリ文字列を送信する。
443
+ *
444
+ * 実験的: APIが変わる可能性があります。
445
+ */
446
+ static VALUE
447
+ rb_grn_context_send (VALUE self, VALUE rb_string)
448
+ {
449
+ grn_ctx *context;
450
+ char *string;
451
+ unsigned int string_size;
452
+ int flags = 0;
453
+ unsigned int query_id;
454
+
455
+ context = SELF(self);
456
+ string = StringValuePtr(rb_string);
457
+ string_size = RSTRING_LEN(rb_string);
458
+ query_id = grn_ctx_send(context, string, string_size, flags);
459
+ rb_grn_context_check(context, self);
460
+
461
+ return UINT2NUM(query_id);
462
+ }
463
+
464
+ /*
465
+ * call-seq:
466
+ * context.receive -> [ID, String]
467
+ *
468
+ * groongaサーバからクエリ実行結果文字列を受信する。
469
+ *
470
+ * 実験的: APIが変わる可能性があります。
471
+ */
472
+ static VALUE
473
+ rb_grn_context_receive (VALUE self)
474
+ {
475
+ grn_ctx *context;
476
+ char *string;
477
+ unsigned string_size;
478
+ int flags = 0;
479
+ unsigned int query_id;
480
+
481
+ context = SELF(self);
482
+ query_id = grn_ctx_recv(context, &string, &string_size, &flags);
483
+ rb_grn_context_check(context, self);
484
+
485
+ return rb_ary_new3(2, UINT2NUM(query_id), rb_str_new(string, string_size));
486
+ }
487
+
354
488
  static const char *
355
489
  grn_type_name_old_to_new (const char *name, unsigned int name_size)
356
490
  {
@@ -472,6 +606,14 @@ rb_grn_context_array_reference (VALUE self, VALUE name_or_id)
472
606
  return GRNOBJECT2RVAL(Qnil, context, object, RB_GRN_FALSE);
473
607
  }
474
608
 
609
+ static VALUE
610
+ rb_grn_context_pop (VALUE self)
611
+ {
612
+ grn_ctx *context;
613
+ context = SELF(self);
614
+ return GRNOBJ2RVAL(Qnil, context, grn_ctx_pop(context), self);
615
+ }
616
+
475
617
  void
476
618
  rb_grn_init_context (VALUE mGrn)
477
619
  {
@@ -500,4 +642,10 @@ rb_grn_init_context (VALUE mGrn)
500
642
  rb_define_method(cGrnContext, "database", rb_grn_context_get_database, 0);
501
643
 
502
644
  rb_define_method(cGrnContext, "[]", rb_grn_context_array_reference, 1);
645
+
646
+ rb_define_method(cGrnContext, "pop", rb_grn_context_pop, 0);
647
+
648
+ rb_define_method(cGrnContext, "connect", rb_grn_context_connect, -1);
649
+ rb_define_method(cGrnContext, "send", rb_grn_context_send, 1);
650
+ rb_define_method(cGrnContext, "receive", rb_grn_context_receive, 0);
503
651
  }