groonga 0.0.6 → 0.0.7

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