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
@@ -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
  }