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
@@ -78,11 +78,15 @@ rb_grn_object_from_ruby_object (VALUE object, grn_ctx **context)
78
78
  return rb_grn_object->object;
79
79
  }
80
80
 
81
- grn_rc
82
- rb_grn_object_finalizer (grn_ctx *context, grn_obj *grn_object,
81
+ static grn_obj *
82
+ rb_grn_object_finalizer (grn_ctx *context, int n_args, grn_obj **grn_objects,
83
83
  grn_user_data *user_data)
84
84
  {
85
85
  RbGrnObject *rb_grn_object;
86
+ grn_obj *grn_object = *grn_objects;
87
+
88
+ if (rb_grn_exited)
89
+ return NULL;
86
90
 
87
91
  rb_grn_object = user_data->ptr;
88
92
 
@@ -137,7 +141,7 @@ rb_grn_object_finalizer (grn_ctx *context, grn_obj *grn_object,
137
141
  break;
138
142
  }
139
143
 
140
- return GRN_SUCCESS;
144
+ return NULL;
141
145
  }
142
146
 
143
147
  void
@@ -149,12 +153,12 @@ rb_grn_object_free (RbGrnObject *rb_grn_object)
149
153
  context = rb_grn_object->context;
150
154
  grn_object = rb_grn_object->object;
151
155
  debug("rb-free: %p:%p:%p\n", context, grn_object, rb_grn_object);
152
- if (context && grn_object) {
156
+ if (!rb_grn_exited && context && grn_object) {
153
157
  rb_grn_object->context = NULL;
154
158
  rb_grn_object->object = NULL;
155
159
  debug("type: %x\n", grn_object->header.type);
156
160
  if (rb_grn_object->need_close) {
157
- grn_obj_close(context, grn_object);
161
+ grn_obj_unlink(context, grn_object);
158
162
  }
159
163
  }
160
164
  xfree(rb_grn_object);
@@ -599,8 +603,8 @@ rb_grn_object_inspect_content_flags (VALUE inspected,
599
603
  rb_ary_push(inspected_flags, rb_str_new2("TABLE_PAT_KEY"));
600
604
  if (flags & GRN_OBJ_TABLE_NO_KEY)
601
605
  rb_ary_push(inspected_flags, rb_str_new2("TABLE_NO_KEY"));
602
- if (flags & GRN_OBJ_TABLE_ALIAS)
603
- rb_ary_push(inspected_flags, rb_str_new2("TABLE_ALIAS"));
606
+ if (flags & GRN_OBJ_TABLE_VIEW)
607
+ rb_ary_push(inspected_flags, rb_str_new2("TABLE_VIEW"));
604
608
  }
605
609
 
606
610
  switch (object->header.type) {
@@ -1048,7 +1052,7 @@ rb_grn_object_array_set (VALUE self, VALUE rb_id, VALUE rb_value)
1048
1052
  * call-seq:
1049
1053
  * object.append(id, value)
1050
1054
  *
1051
- * _object_の_id_に対応する値に_value_を追加する。
1055
+ * _object_の_id_に対応する値の最後に_value_を追加する。
1052
1056
  */
1053
1057
  static VALUE
1054
1058
  rb_grn_object_append_value (VALUE self, VALUE rb_id, VALUE rb_value)
@@ -1056,6 +1060,20 @@ rb_grn_object_append_value (VALUE self, VALUE rb_id, VALUE rb_value)
1056
1060
  return rb_grn_object_set(self, rb_id, rb_value, GRN_OBJ_APPEND);
1057
1061
  }
1058
1062
 
1063
+ /*
1064
+ * Document-method: prepend
1065
+ *
1066
+ * call-seq:
1067
+ * object.prepend(id, value)
1068
+ *
1069
+ * _object_の_id_に対応する値の最初に_value_を追加する。
1070
+ */
1071
+ static VALUE
1072
+ rb_grn_object_prepend_value (VALUE self, VALUE rb_id, VALUE rb_value)
1073
+ {
1074
+ return rb_grn_object_set(self, rb_id, rb_value, GRN_OBJ_PREPEND);
1075
+ }
1076
+
1059
1077
  static VALUE
1060
1078
  rb_grn_object_remove (VALUE self)
1061
1079
  {
@@ -1097,6 +1115,7 @@ rb_grn_init_object (VALUE mGrn)
1097
1115
  rb_define_method(rb_cGrnObject, "[]", rb_grn_object_array_reference, 1);
1098
1116
  rb_define_method(rb_cGrnObject, "[]=", rb_grn_object_array_set, 2);
1099
1117
  rb_define_method(rb_cGrnObject, "append", rb_grn_object_append_value, 2);
1118
+ rb_define_method(rb_cGrnObject, "prepend", rb_grn_object_prepend_value, 2);
1100
1119
 
1101
1120
  rb_define_method(rb_cGrnObject, "remove", rb_grn_object_remove, 0);
1102
1121
  }
@@ -25,40 +25,64 @@ rb_grn_init_operation (VALUE mGrn)
25
25
  {
26
26
  rb_mGrnOperation = rb_define_module_under(mGrn, "Operation");
27
27
 
28
- rb_define_const(rb_mGrnOperation, "NO_OPERATION",
29
- UINT2NUM(GRN_OP_NOP));
30
28
  rb_define_const(rb_mGrnOperation, "PUSH",
31
29
  UINT2NUM(GRN_OP_PUSH));
32
30
  rb_define_const(rb_mGrnOperation, "POP",
33
31
  UINT2NUM(GRN_OP_POP));
32
+ rb_define_const(rb_mGrnOperation, "NO_OPERATION",
33
+ UINT2NUM(GRN_OP_NOP));
34
34
  rb_define_const(rb_mGrnOperation, "CALL",
35
35
  UINT2NUM(GRN_OP_CALL));
36
36
  rb_define_const(rb_mGrnOperation, "INTERN",
37
37
  UINT2NUM(GRN_OP_INTERN));
38
- rb_define_const(rb_mGrnOperation, "TABLE_CREATE",
39
- UINT2NUM(GRN_OP_TABLE_CREATE));
40
- rb_define_const(rb_mGrnOperation, "EXPRESSION_GET_VARIABLE",
41
- UINT2NUM(GRN_OP_EXPR_GET_VAR));
42
- rb_define_const(rb_mGrnOperation, "VARIABLE_SET_VALUE",
43
- UINT2NUM(GRN_OP_VAR_SET_VALUE));
44
- rb_define_const(rb_mGrnOperation, "OBJECT_GET_VALUE",
45
- UINT2NUM(GRN_OP_OBJ_GET_VALUE));
46
- rb_define_const(rb_mGrnOperation, "OBJECT_SET_VALUE",
47
- UINT2NUM(GRN_OP_OBJ_SET_VALUE));
48
- rb_define_const(rb_mGrnOperation, "OBJECT_SEARCH",
49
- UINT2NUM(GRN_OP_OBJ_SEARCH));
50
- rb_define_const(rb_mGrnOperation, "TABLE_SELECT",
51
- UINT2NUM(GRN_OP_TABLE_SELECT));
52
- rb_define_const(rb_mGrnOperation, "TABLE_SORT",
53
- UINT2NUM(GRN_OP_TABLE_SORT));
54
- rb_define_const(rb_mGrnOperation, "TABLE_GROUP",
55
- UINT2NUM(GRN_OP_TABLE_GROUP));
56
- rb_define_const(rb_mGrnOperation, "JSON_PUT",
57
- UINT2NUM(GRN_OP_JSON_PUT));
38
+ rb_define_const(rb_mGrnOperation, "GET_REFERENCE",
39
+ UINT2NUM(GRN_OP_GET_REF));
40
+ rb_define_const(rb_mGrnOperation, "GET_VALUE",
41
+ UINT2NUM(GRN_OP_GET_VALUE));
58
42
  rb_define_const(rb_mGrnOperation, "AND",
59
43
  UINT2NUM(GRN_OP_AND));
44
+ rb_define_const(rb_mGrnOperation, "BUT",
45
+ UINT2NUM(GRN_OP_BUT));
60
46
  rb_define_const(rb_mGrnOperation, "OR",
61
47
  UINT2NUM(GRN_OP_OR));
48
+ rb_define_const(rb_mGrnOperation, "ASSIGN",
49
+ UINT2NUM(GRN_OP_ASSIGN));
50
+ rb_define_const(rb_mGrnOperation, "STAR_ASSIGN",
51
+ UINT2NUM(GRN_OP_STAR_ASSIGN));
52
+ rb_define_const(rb_mGrnOperation, "SLASH_ASSIGN",
53
+ UINT2NUM(GRN_OP_SLASH_ASSIGN));
54
+ rb_define_const(rb_mGrnOperation, "MODULO_ASSIGN",
55
+ UINT2NUM(GRN_OP_MOD_ASSIGN));
56
+ rb_define_const(rb_mGrnOperation, "PLUS_ASSIGN",
57
+ UINT2NUM(GRN_OP_PLUS_ASSIGN));
58
+ rb_define_const(rb_mGrnOperation, "MINUS_ASSIGN",
59
+ UINT2NUM(GRN_OP_MINUS_ASSIGN));
60
+ rb_define_const(rb_mGrnOperation, "SHIFTL_ASSIGN",
61
+ UINT2NUM(GRN_OP_SHIFTL_ASSIGN));
62
+ rb_define_const(rb_mGrnOperation, "SHIRTR_ASSIGN",
63
+ UINT2NUM(GRN_OP_SHIRTR_ASSIGN));
64
+ rb_define_const(rb_mGrnOperation, "SHIFTRR_ASSIGN",
65
+ UINT2NUM(GRN_OP_SHIFTRR_ASSIGN));
66
+ rb_define_const(rb_mGrnOperation, "AND_ASSIGN",
67
+ UINT2NUM(GRN_OP_AND_ASSIGN));
68
+ rb_define_const(rb_mGrnOperation, "XOR_ASSIGN",
69
+ UINT2NUM(GRN_OP_XOR_ASSIGN));
70
+ rb_define_const(rb_mGrnOperation, "OR_ASSIGN",
71
+ UINT2NUM(GRN_OP_OR_ASSIGN));
72
+ rb_define_const(rb_mGrnOperation, "JUMP",
73
+ UINT2NUM(GRN_OP_JUMP));
74
+ rb_define_const(rb_mGrnOperation, "CJUMP",
75
+ UINT2NUM(GRN_OP_CJUMP));
76
+ rb_define_const(rb_mGrnOperation, "COMMA",
77
+ UINT2NUM(GRN_OP_COMMA));
78
+ rb_define_const(rb_mGrnOperation, "BITWISE_OR",
79
+ UINT2NUM(GRN_OP_BITWISE_OR));
80
+ rb_define_const(rb_mGrnOperation, "BITWISE_XOR",
81
+ UINT2NUM(GRN_OP_BITWISE_XOR));
82
+ rb_define_const(rb_mGrnOperation, "BITWISE_AND",
83
+ UINT2NUM(GRN_OP_BITWISE_AND));
84
+ rb_define_const(rb_mGrnOperation, "BITWISE_NOT",
85
+ UINT2NUM(GRN_OP_BITWISE_NOT));
62
86
  rb_define_const(rb_mGrnOperation, "EQUAL",
63
87
  UINT2NUM(GRN_OP_EQUAL));
64
88
  rb_define_const(rb_mGrnOperation, "NOT_EQUAL",
@@ -71,8 +95,90 @@ rb_grn_init_operation (VALUE mGrn)
71
95
  UINT2NUM(GRN_OP_LESS_EQUAL));
72
96
  rb_define_const(rb_mGrnOperation, "GREATER_EQUAL",
73
97
  UINT2NUM(GRN_OP_GREATER_EQUAL));
98
+ rb_define_const(rb_mGrnOperation, "IN",
99
+ UINT2NUM(GRN_OP_IN));
74
100
  rb_define_const(rb_mGrnOperation, "MATCH",
75
101
  UINT2NUM(GRN_OP_MATCH));
102
+ rb_define_const(rb_mGrnOperation, "NEAR",
103
+ UINT2NUM(GRN_OP_NEAR));
104
+ rb_define_const(rb_mGrnOperation, "NEAR2",
105
+ UINT2NUM(GRN_OP_NEAR2));
106
+ rb_define_const(rb_mGrnOperation, "SIMILAR",
107
+ UINT2NUM(GRN_OP_SIMILAR));
108
+ rb_define_const(rb_mGrnOperation, "TERM_EXTRACT",
109
+ UINT2NUM(GRN_OP_TERM_EXTRACT));
110
+ rb_define_const(rb_mGrnOperation, "SHIFTL",
111
+ UINT2NUM(GRN_OP_SHIFTL));
112
+ rb_define_const(rb_mGrnOperation, "SHIFTR",
113
+ UINT2NUM(GRN_OP_SHIFTR));
114
+ rb_define_const(rb_mGrnOperation, "SHIFTRR",
115
+ UINT2NUM(GRN_OP_SHIFTRR));
116
+ rb_define_const(rb_mGrnOperation, "PLUS",
117
+ UINT2NUM(GRN_OP_PLUS));
118
+ rb_define_const(rb_mGrnOperation, "MINUS",
119
+ UINT2NUM(GRN_OP_MINUS));
120
+ rb_define_const(rb_mGrnOperation, "STAR",
121
+ UINT2NUM(GRN_OP_STAR));
122
+ rb_define_const(rb_mGrnOperation, "SLASH",
123
+ UINT2NUM(GRN_OP_SLASH));
124
+ rb_define_const(rb_mGrnOperation, "MODULO",
125
+ UINT2NUM(GRN_OP_MOD));
126
+ rb_define_const(rb_mGrnOperation, "DELETE",
127
+ UINT2NUM(GRN_OP_DELETE));
128
+ rb_define_const(rb_mGrnOperation, "INCREMENT",
129
+ UINT2NUM(GRN_OP_INCR));
130
+ rb_define_const(rb_mGrnOperation, "DECREMENT",
131
+ UINT2NUM(GRN_OP_DECR));
132
+ rb_define_const(rb_mGrnOperation, "INCREMENT_POST",
133
+ UINT2NUM(GRN_OP_INCR_POST));
134
+ rb_define_const(rb_mGrnOperation, "DECREMENT_POST",
135
+ UINT2NUM(GRN_OP_DECR_POST));
136
+ rb_define_const(rb_mGrnOperation, "NOT",
137
+ UINT2NUM(GRN_OP_NOT));
138
+ rb_define_const(rb_mGrnOperation, "ADJUST",
139
+ UINT2NUM(GRN_OP_ADJUST));
140
+ rb_define_const(rb_mGrnOperation, "EXACT",
141
+ UINT2NUM(GRN_OP_EXACT));
142
+ rb_define_const(rb_mGrnOperation, "LONGEST_COMMON_PREFIX",
143
+ UINT2NUM(GRN_OP_LCP));
144
+ rb_define_const(rb_mGrnOperation, "PARTIAL",
145
+ UINT2NUM(GRN_OP_PARTIAL));
146
+ rb_define_const(rb_mGrnOperation, "UNSPLIT",
147
+ UINT2NUM(GRN_OP_UNSPLIT));
148
+ rb_define_const(rb_mGrnOperation, "PREFIX",
149
+ UINT2NUM(GRN_OP_PREFIX));
150
+ rb_define_const(rb_mGrnOperation, "SUFFIX",
151
+ UINT2NUM(GRN_OP_SUFFIX));
152
+ rb_define_const(rb_mGrnOperation, "GEO_DISTANCE1",
153
+ UINT2NUM(GRN_OP_GEO_DISTANCE1));
154
+ rb_define_const(rb_mGrnOperation, "GEO_DISTANCE2",
155
+ UINT2NUM(GRN_OP_GEO_DISTANCE2));
156
+ rb_define_const(rb_mGrnOperation, "GEO_DISTANCE3",
157
+ UINT2NUM(GRN_OP_GEO_DISTANCE3));
158
+ rb_define_const(rb_mGrnOperation, "GEO_DISTANCE4",
159
+ UINT2NUM(GRN_OP_GEO_DISTANCE4));
160
+ rb_define_const(rb_mGrnOperation, "GEO_WITHINP5",
161
+ UINT2NUM(GRN_OP_GEO_WITHINP5));
162
+ rb_define_const(rb_mGrnOperation, "GEO_WITHINP6",
163
+ UINT2NUM(GRN_OP_GEO_WITHINP6));
164
+ rb_define_const(rb_mGrnOperation, "GEO_WITHINP8",
165
+ UINT2NUM(GRN_OP_GEO_WITHINP8));
166
+ rb_define_const(rb_mGrnOperation, "OBJECT_SEARCH",
167
+ UINT2NUM(GRN_OP_OBJ_SEARCH));
168
+ rb_define_const(rb_mGrnOperation, "EXPRESSION_GET_VARIABLE",
169
+ UINT2NUM(GRN_OP_EXPR_GET_VAR));
170
+ rb_define_const(rb_mGrnOperation, "TABLE_CREATE",
171
+ UINT2NUM(GRN_OP_TABLE_CREATE));
172
+ rb_define_const(rb_mGrnOperation, "TABLE_SELECT",
173
+ UINT2NUM(GRN_OP_TABLE_SELECT));
174
+ rb_define_const(rb_mGrnOperation, "TABLE_SORT",
175
+ UINT2NUM(GRN_OP_TABLE_SORT));
176
+ rb_define_const(rb_mGrnOperation, "TABLE_GROUP",
177
+ UINT2NUM(GRN_OP_TABLE_GROUP));
178
+ rb_define_const(rb_mGrnOperation, "JSON_PUT",
179
+ UINT2NUM(GRN_OP_JSON_PUT));
180
+
181
+
76
182
  /*
77
183
  rb_define_const(rb_mGrnOperation, "GEO_DISTANCE1",
78
184
  UINT2NUM(GRN_OP_GEO_DISTANCE1));
@@ -150,6 +150,66 @@ rb_grn_patricia_trie_search (int argc, VALUE *argv, VALUE self)
150
150
  return rb_result;
151
151
  }
152
152
 
153
+ static VALUE
154
+ rb_grn_patricia_trie_scan (VALUE self, VALUE rb_string)
155
+ {
156
+ grn_ctx *context;
157
+ grn_obj *table;
158
+ VALUE rb_result = Qnil;
159
+ grn_pat_scan_hit hits[1024];
160
+ const char *string;
161
+ long string_length;
162
+ rb_grn_boolean block_given;
163
+
164
+ string = StringValuePtr(rb_string);
165
+ string_length = RSTRING_LEN(rb_string);
166
+
167
+ rb_grn_table_key_support_deconstruct(SELF(self), &table, &context,
168
+ NULL, NULL, NULL,
169
+ NULL, NULL, NULL);
170
+
171
+ block_given = rb_block_given_p();
172
+ if (!block_given)
173
+ rb_result = rb_ary_new();
174
+
175
+ while (string_length > 0) {
176
+ const char *rest;
177
+ int i, n_hits;
178
+ long previous_offset = 0;
179
+
180
+ n_hits = grn_pat_scan(context, (grn_pat *)table,
181
+ string, string_length,
182
+ hits, sizeof(hits) / sizeof(*hits),
183
+ &rest);
184
+ for (i = 0; i < n_hits; i++) {
185
+ VALUE record, term, matched_info;
186
+
187
+ if (hits[i].offset < previous_offset)
188
+ continue;
189
+
190
+ record = rb_grn_record_new(self, hits[i].id, Qnil);
191
+ term = rb_grn_context_rb_string_new(context,
192
+ string + hits[i].offset,
193
+ hits[i].length);
194
+ matched_info = rb_ary_new3(4,
195
+ record,
196
+ term,
197
+ UINT2NUM(hits[i].offset),
198
+ UINT2NUM(hits[i].length));
199
+ if (block_given) {
200
+ rb_yield(matched_info);
201
+ } else {
202
+ rb_ary_push(rb_result, matched_info);
203
+ }
204
+ previous_offset = hits[i].offset;
205
+ }
206
+ string_length -= rest - string;
207
+ string = rest;
208
+ }
209
+
210
+ return rb_result;
211
+ }
212
+
153
213
  void
154
214
  rb_grn_init_patricia_trie (VALUE mGrn)
155
215
  {
@@ -162,4 +222,6 @@ rb_grn_init_patricia_trie (VALUE mGrn)
162
222
 
163
223
  rb_define_method(rb_cGrnPatriciaTrie, "search",
164
224
  rb_grn_patricia_trie_search, -1);
225
+ rb_define_method(rb_cGrnPatriciaTrie, "scan",
226
+ rb_grn_patricia_trie_scan, 1);
165
227
  }
@@ -18,10 +18,6 @@
18
18
 
19
19
  #include "rb-grn.h"
20
20
 
21
- #ifdef HAVE_RUBY_ENCODING_H
22
- # include <ruby/encoding.h>
23
- #endif
24
-
25
21
  #define SELF(object) (rb_rb_grn_snippet_from_ruby_object(object))
26
22
 
27
23
  typedef struct _RbGrnSnippet RbGrnSnippet;
@@ -73,7 +69,8 @@ rb_rb_grn_snippet_free (void *object)
73
69
  }
74
70
 
75
71
  VALUE
76
- rb_grn_snippet_to_ruby_object (grn_ctx *context, grn_snip *snippet)
72
+ rb_grn_snippet_to_ruby_object (grn_ctx *context, grn_snip *snippet,
73
+ rb_grn_boolean owner)
77
74
  {
78
75
  RbGrnSnippet *rb_grn_snippet;
79
76
 
@@ -83,7 +80,7 @@ rb_grn_snippet_to_ruby_object (grn_ctx *context, grn_snip *snippet)
83
80
  rb_grn_snippet = ALLOC(RbGrnSnippet);
84
81
  rb_grn_snippet->context = context;
85
82
  rb_grn_snippet->snippet = snippet;
86
- rb_grn_snippet->owner = RB_GRN_FALSE;
83
+ rb_grn_snippet->owner = owner;
87
84
 
88
85
  return Data_Wrap_Struct(rb_cGrnSnippet, NULL,
89
86
  rb_rb_grn_snippet_free, rb_grn_snippet);
@@ -224,19 +221,16 @@ rb_grn_snippet_execute (VALUE self, VALUE rb_string)
224
221
  unsigned int i, n_results, max_tagged_length;
225
222
  VALUE rb_results;
226
223
  char *result;
227
- #ifdef HAVE_RUBY_ENCODING_H
228
- rb_encoding *encoding;
229
- #endif
230
224
 
231
225
  rb_grn_snippet = SELF(self);
232
226
  context = rb_grn_snippet->context;
233
227
  snippet = rb_grn_snippet->snippet;
234
228
 
235
- string = StringValuePtr(rb_string);
236
- string_length = RSTRING_LEN(rb_string);
237
229
  #ifdef HAVE_RUBY_ENCODING_H
238
- encoding = rb_enc_get(rb_string);
230
+ rb_string = rb_grn_context_rb_string_encode(context, rb_string);
239
231
  #endif
232
+ string = StringValuePtr(rb_string);
233
+ string_length = RSTRING_LEN(rb_string);
240
234
 
241
235
  rc = grn_snip_exec(context, snippet, string, string_length,
242
236
  &n_results, &max_tagged_length);
@@ -250,11 +244,7 @@ rb_grn_snippet_execute (VALUE self, VALUE rb_string)
250
244
 
251
245
  rc = grn_snip_get_result(context, snippet, i, result, &result_length);
252
246
  rb_grn_rc_check(rc, self);
253
- #ifdef HAVE_RUBY_ENCODING_H
254
- rb_result = rb_enc_str_new(result, result_length, encoding);
255
- #else
256
- rb_result = rb_str_new(result, result_length);
257
- #endif
247
+ rb_result = rb_grn_context_rb_string_new(context, result, result_length);
258
248
  rb_ary_push(rb_results, rb_result);
259
249
  }
260
250
 
@@ -813,9 +813,9 @@ rb_grn_table_sort (int argc, VALUE *argv, VALUE self)
813
813
  grn_obj *result;
814
814
  grn_table_sort_key *keys;
815
815
  int i, n_keys;
816
- int n_records, limit = 0;
816
+ int n_records, offset = 0, limit = -1;
817
817
  VALUE rb_keys, options;
818
- VALUE rb_limit;
818
+ VALUE rb_offset, rb_limit;
819
819
  VALUE *rb_sort_keys;
820
820
  grn_table_cursor *cursor;
821
821
  VALUE rb_result;
@@ -876,15 +876,19 @@ rb_grn_table_sort (int argc, VALUE *argv, VALUE self)
876
876
  }
877
877
 
878
878
  rb_grn_scan_options(options,
879
+ "offset", &rb_offset,
879
880
  "limit", &rb_limit,
880
881
  NULL);
881
882
 
883
+ if (!NIL_P(rb_offset))
884
+ offset = NUM2INT(rb_offset);
882
885
  if (!NIL_P(rb_limit))
883
886
  limit = NUM2INT(rb_limit);
884
887
 
885
888
  result = grn_table_create(context, NULL, 0, NULL, GRN_TABLE_NO_KEY,
886
889
  NULL, table);
887
- n_records = grn_table_sort(context, table, limit, result, keys, n_keys);
890
+ n_records = grn_table_sort(context, table, offset, limit,
891
+ result, keys, n_keys);
888
892
 
889
893
  rb_result = rb_ary_new();
890
894
  cursor = grn_table_cursor_open(context, result, NULL, 0, NULL, 0,
@@ -1240,13 +1244,93 @@ rb_grn_table_is_locked (int argc, VALUE *argv, VALUE self)
1240
1244
  return CBOOL2RVAL(grn_obj_is_locked(context, table));
1241
1245
  }
1242
1246
 
1247
+ /*
1248
+ * call-seq:
1249
+ * table.select(options) {|record| ...} -> Groonga::Hash
1250
+ * table.select(query, options) -> Groonga::Hash
1251
+ *
1252
+ * _table_からブロックまたは文字列で指定した条件にマッチする
1253
+ * レコードを返す。返されたテーブルには+expression+という特
1254
+ * 異メソッドがあり、指定した条件を表している
1255
+ * Groonga::Expressionを取得できる。
1256
+ * Groonga::Expression#snippetを使うことにより、指定した条件
1257
+ * 用のスニペットを簡単に生成できる。
1258
+ *
1259
+ * results = table.select do |record|
1260
+ * result["description"] =~ "groonga"
1261
+ * end
1262
+ * snippet = results.expression.snippet([["<em>", "</em>"]])
1263
+ * results.each do |record|
1264
+ * puts "#{record['name']}の説明文の中で「groonga」が含まれる部分"
1265
+ * snippet.execute(record["description"].each do |snippet|
1266
+ * puts "---"
1267
+ * puts "#{snippet}..."
1268
+ * puts "---"
1269
+ * end
1270
+ * end
1271
+ *
1272
+ * 出力例
1273
+ * Ruby/groongaの説明文の中で「groonga」が含まれる部分
1274
+ * ---
1275
+ * Ruby/<em>groonga</em>は<em>groonga</em>のいわゆるDB-APIの層の...
1276
+ * ---
1277
+ *
1278
+ * _query_には「[カラム名]:[演算子][値]」という書式で条件を
1279
+ * 指定する。演算子は以下の通り。
1280
+ *
1281
+ * [なし]
1282
+ * [カラム値] == [値]
1283
+ * [+!+]
1284
+ * [カラム値] != [値]
1285
+ * [+<+]
1286
+ * [カラム値] < [値]
1287
+ * [+>+]
1288
+ * [カラム値] > [値]
1289
+ * [+<=+]
1290
+ * [カラム値] <= [値]
1291
+ * [+>=+]
1292
+ * [カラム値] >= [値]
1293
+ * [+@+]
1294
+ * [カラム値]が[値]を含んでいるかどうか
1295
+ *
1296
+ * 例:
1297
+ * "name:daijiro" # "name"カラムの値が"daijiro"のレコードにマッチ
1298
+ * "description:@groonga" # "description"カラムに
1299
+ * # "groonga"を含んでいるレコードにマッチ
1300
+ *
1301
+ * ブロックで条件を指定する場合はGroonga::ExpressionBuilder
1302
+ * を参照。
1303
+ *
1304
+ * _options_に指定可能な値は以下の通り。
1305
+ *
1306
+ * [+:operator+]
1307
+ * マッチしたレコードをどのように扱うか。指定可能な値は以
1308
+ * 下の通り。省略した場合はGroonga::Operation::OR。
1309
+ *
1310
+ * [Groonga::Operation::OR]
1311
+ * マッチしたレコードを追加。すでにレコードが追加され
1312
+ * ている場合は何もしない。
1313
+ * [Groonga::Operation::AND]
1314
+ * マッチしたレコードのスコアを増加。マッチしなかった
1315
+ * レコードを削除。
1316
+ * [Groonga::Operation::BUT]
1317
+ * マッチしたレコードを削除。
1318
+ * [Groonga::Operation::ADJUST]
1319
+ * マッチしたレコードのスコアを増加。
1320
+ *
1321
+ * [+:result+]
1322
+ * 検索結果を格納するテーブル。マッチしたレコードが追加さ
1323
+ * れていく。省略した場合は新しくテーブルを作成して返す。
1324
+ *
1325
+ * [+:name+]
1326
+ * 条件の名前。省略した場合は名前を付けない。
1327
+ */
1243
1328
  static VALUE
1244
1329
  rb_grn_table_select (int argc, VALUE *argv, VALUE self)
1245
1330
  {
1246
1331
  grn_ctx *context;
1247
1332
  grn_obj *table, *result, *expression;
1248
1333
  grn_operator operator = GRN_OP_OR;
1249
- grn_rc rc;
1250
1334
  VALUE rb_query = Qnil, query_or_options, options;
1251
1335
  VALUE rb_name, rb_operator, rb_result;
1252
1336
  VALUE rb_expression, builder;
@@ -1258,11 +1342,6 @@ rb_grn_table_select (int argc, VALUE *argv, VALUE self)
1258
1342
  NULL, NULL, NULL);
1259
1343
 
1260
1344
  if (RVAL2CBOOL(rb_obj_is_kind_of(query_or_options, rb_cString))) {
1261
- if (rb_block_given_p())
1262
- rb_raise(rb_eArgError,
1263
- "should not specify both of query string and "
1264
- "expression block: %s",
1265
- rb_grn_inspect(rb_ary_new4(argc, argv)));
1266
1345
  rb_query = query_or_options;
1267
1346
  } else {
1268
1347
  if (!NIL_P(options))
@@ -1292,31 +1371,22 @@ rb_grn_table_select (int argc, VALUE *argv, VALUE self)
1292
1371
  result = RVAL2GRNTABLE(rb_result, &context);
1293
1372
  }
1294
1373
 
1295
- if (NIL_P(rb_query)) {
1296
- builder = rb_grn_record_expression_builder_new(self, rb_name);
1297
- rb_expression = rb_grn_record_expression_builder_build(builder);
1298
- rb_grn_object_deconstruct(RB_GRN_OBJECT(DATA_PTR(rb_expression)),
1299
- &expression, NULL,
1300
- NULL, NULL, NULL, NULL);
1301
- } else {
1302
- const char *name = NULL, *query;
1303
- unsigned name_size = 0, query_size;
1304
-
1305
- query = StringValueCStr(rb_query);
1306
- query_size = RSTRING_LEN(rb_query);
1307
- if (!NIL_P(rb_name)) {
1308
- name = StringValueCStr(rb_name);
1309
- name_size = RSTRING_LEN(rb_name);
1310
- }
1311
- expression = grn_expr_create_from_str(context, name, name_size,
1312
- query, query_size,
1313
- table, NULL);
1374
+ builder = rb_grn_record_expression_builder_new(self, rb_name);
1375
+ if (!NIL_P(rb_query)) {
1376
+ rb_funcall(builder, rb_intern("query="), 1, rb_query);
1314
1377
  }
1378
+ rb_expression = rb_grn_record_expression_builder_build(builder);
1379
+ rb_grn_object_deconstruct(RB_GRN_OBJECT(DATA_PTR(rb_expression)),
1380
+ &expression, NULL,
1381
+ NULL, NULL, NULL, NULL);
1315
1382
 
1316
-
1317
- rc = grn_table_select(context, table, expression, result, operator);
1383
+ grn_table_select(context, table, expression, result, operator);
1318
1384
  rb_grn_context_check(context, self);
1319
- rb_grn_rc_check(rc, self);
1385
+
1386
+ rb_attr(rb_singleton_class(rb_result),
1387
+ rb_intern("expression"),
1388
+ RB_GRN_TRUE, RB_GRN_FALSE, RB_GRN_FALSE);
1389
+ rb_iv_set(rb_result, "@expression", rb_expression);
1320
1390
 
1321
1391
  return rb_result;
1322
1392
  }