groonga 0.0.7 → 0.9.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 (102) hide show
  1. data/NEWS.ja.rdoc +56 -0
  2. data/NEWS.rdoc +58 -0
  3. data/Rakefile +2 -3
  4. data/benchmark/read-write-many-small-items.rb +16 -32
  5. data/benchmark/write-many-small-items.rb +14 -28
  6. data/example/bookmark.rb +19 -17
  7. data/example/index-html.rb +11 -1
  8. data/example/search/config.ru +14 -9
  9. data/ext/rb-grn-array.c +6 -6
  10. data/ext/rb-grn-column.c +348 -18
  11. data/ext/rb-grn-context.c +8 -4
  12. data/ext/rb-grn-database.c +6 -7
  13. data/ext/rb-grn-exception.c +101 -5
  14. data/ext/rb-grn-expression.c +206 -23
  15. data/ext/rb-grn-fix-size-column.c +6 -39
  16. data/ext/rb-grn-hash.c +24 -24
  17. data/ext/rb-grn-index-column.c +74 -19
  18. data/ext/rb-grn-logger.c +48 -0
  19. data/ext/rb-grn-object.c +281 -67
  20. data/ext/rb-grn-operation.c +1 -1
  21. data/ext/rb-grn-patricia-trie-cursor.c +10 -1
  22. data/ext/rb-grn-patricia-trie.c +268 -7
  23. data/ext/rb-grn-query.c +52 -1
  24. data/ext/rb-grn-record.c +8 -2
  25. data/ext/rb-grn-snippet.c +63 -1
  26. data/ext/rb-grn-table-cursor-key-support.c +15 -1
  27. data/ext/rb-grn-table-cursor.c +57 -0
  28. data/ext/rb-grn-table-key-support.c +382 -46
  29. data/ext/rb-grn-table.c +729 -192
  30. data/ext/rb-grn-type.c +63 -12
  31. data/ext/rb-grn-utils.c +156 -158
  32. data/ext/rb-grn-variable.c +18 -0
  33. data/ext/rb-grn.h +85 -21
  34. data/ext/rb-groonga.c +13 -3
  35. data/extconf.rb +19 -4
  36. data/html/developer.html +1 -1
  37. data/html/header.html.erb +1 -1
  38. data/html/index.html +4 -4
  39. data/lib/groonga.rb +10 -0
  40. data/lib/groonga/expression-builder.rb +81 -42
  41. data/lib/groonga/patricia-trie.rb +13 -0
  42. data/lib/groonga/record.rb +158 -13
  43. data/lib/groonga/schema.rb +339 -33
  44. data/pkg-config.rb +6 -1
  45. data/test-unit/lib/test/unit.rb +23 -42
  46. data/test-unit/lib/test/unit/assertionfailederror.rb +11 -0
  47. data/test-unit/lib/test/unit/assertions.rb +87 -9
  48. data/test-unit/lib/test/unit/autorunner.rb +20 -11
  49. data/test-unit/lib/test/unit/collector.rb +1 -8
  50. data/test-unit/lib/test/unit/collector/load.rb +2 -3
  51. data/test-unit/lib/test/unit/color-scheme.rb +13 -1
  52. data/test-unit/lib/test/unit/diff.rb +223 -37
  53. data/test-unit/lib/test/unit/error.rb +4 -0
  54. data/test-unit/lib/test/unit/failure.rb +31 -5
  55. data/test-unit/lib/test/unit/notification.rb +8 -4
  56. data/test-unit/lib/test/unit/omission.rb +51 -3
  57. data/test-unit/lib/test/unit/pending.rb +4 -0
  58. data/test-unit/lib/test/unit/testcase.rb +55 -4
  59. data/test-unit/lib/test/unit/ui/console/testrunner.rb +190 -4
  60. data/test-unit/lib/test/unit/ui/emacs/testrunner.rb +14 -0
  61. data/test-unit/lib/test/unit/ui/testrunner.rb +8 -0
  62. data/test-unit/lib/test/unit/version.rb +1 -1
  63. data/test-unit/sample/{tc_adder.rb → test_adder.rb} +3 -1
  64. data/test-unit/sample/{tc_subtracter.rb → test_subtracter.rb} +3 -1
  65. data/test-unit/sample/test_user.rb +1 -0
  66. data/test-unit/test/collector/test-descendant.rb +2 -4
  67. data/test-unit/test/collector/test_objectspace.rb +7 -5
  68. data/test-unit/test/run-test.rb +2 -0
  69. data/test-unit/test/test-color-scheme.rb +7 -0
  70. data/test-unit/test/test-diff.rb +48 -7
  71. data/test-unit/test/test-omission.rb +1 -1
  72. data/test-unit/test/test-testcase.rb +47 -0
  73. data/test-unit/test/test_assertions.rb +79 -10
  74. data/test/groonga-test-utils.rb +6 -1
  75. data/test/test-array.rb +29 -14
  76. data/test/test-column.rb +107 -55
  77. data/test/test-context.rb +5 -0
  78. data/test/test-database.rb +2 -37
  79. data/test/test-exception.rb +9 -1
  80. data/test/test-expression-builder.rb +23 -5
  81. data/test/test-expression.rb +44 -8
  82. data/test/test-fix-size-column.rb +16 -5
  83. data/test/test-gqtp.rb +70 -0
  84. data/test/test-hash.rb +142 -43
  85. data/test/test-index-column.rb +9 -9
  86. data/test/test-patricia-trie.rb +79 -20
  87. data/test/test-procedure.rb +4 -2
  88. data/test/test-record.rb +32 -20
  89. data/test/test-remote.rb +3 -2
  90. data/test/test-schema.rb +226 -92
  91. data/test/test-table-cursor.rb +103 -1
  92. data/test/test-table-offset-and-limit.rb +102 -0
  93. data/test/test-table-select-normalize.rb +4 -4
  94. data/test/test-table-select.rb +52 -8
  95. data/test/test-table.rb +235 -116
  96. data/test/test-type.rb +2 -2
  97. data/test/test-variable-size-column.rb +21 -5
  98. data/test/test-vector-column.rb +76 -0
  99. data/{TUTORIAL.ja.rdoc → text/TUTORIAL.ja.rdoc} +52 -52
  100. data/text/expression.rdoc +284 -0
  101. metadata +11 -7
  102. data/test-unit/sample/ts_examples.rb +0 -7
@@ -77,46 +77,13 @@ rb_grn_fix_size_column_array_set (VALUE self, VALUE rb_id, VALUE rb_value)
77
77
  &value, &range_id, &range);
78
78
 
79
79
  id = NUM2UINT(rb_id);
80
-
81
- if (RVAL2CBOOL(rb_obj_is_kind_of(rb_value, rb_cGrnRecord))) {
82
- VALUE rb_id, rb_table;
83
- grn_obj *table;
84
-
85
- if (!range)
86
- rb_raise(rb_eArgError,
87
- "%s isn't associated with any table: %s",
88
- rb_grn_inspect(self), rb_grn_inspect(rb_value));
89
-
90
- rb_id = rb_funcall(rb_value, rb_intern("id"), 0);
91
- rb_table = rb_funcall(rb_value, rb_intern("table"), 0);
92
- table = RVAL2GRNTABLE(rb_table, &context);
93
- if (grn_obj_id(context, table) != range_id)
94
- rb_raise(rb_eArgError,
95
- "%s isn't associated with passed record's table: %s",
96
- rb_grn_inspect(self),
97
- rb_grn_inspect(rb_value));
98
-
99
- rb_value = rb_id;
100
- } else if (range) {
101
- switch (range->header.type) {
102
- case GRN_TABLE_HASH_KEY:
103
- case GRN_TABLE_PAT_KEY:
104
- if (!RVAL2CBOOL(rb_obj_is_kind_of(rb_value, rb_cFixnum))) {
105
- VALUE rb_range;
106
- grn_id id;
107
-
108
- rb_range = GRNOBJECT2RVAL(Qnil, context, range, RB_GRN_FALSE);
109
- id = rb_grn_table_key_support_get(rb_range, rb_value);
110
- rb_value = UINT2NUM(id);
111
- }
112
- break;
113
- default:
114
- break;
115
- }
116
- }
117
-
118
- GRN_BULK_REWIND(value);
119
80
  RVAL2GRNBULK(rb_value, context, value);
81
+ if ((value->header.domain == GRN_DB_INT32 ||
82
+ value->header.domain == GRN_DB_UINT32) &&
83
+ (GRN_TABLE_HASH_KEY <= range->header.type &&
84
+ range->header.type <= GRN_TABLE_VIEW)) {
85
+ value->header.domain = range_id;
86
+ }
120
87
 
121
88
  rc = grn_obj_set_value(context, column, id, value, GRN_OBJ_SET);
122
89
  rb_grn_context_check(context, self);
@@ -63,9 +63,10 @@ VALUE rb_cGrnHash;
63
63
  * タベースの場合は例外が発生する。
64
64
  *
65
65
  * [+:key_type+]
66
- * キーの種類を示すオブジェクトを指定する。キーの種類には
67
- * Groonga::Typeまたはテーブル(Groonga::Array、
68
- * Groonga::Hash、Groonga::PatriciaTrieのどれか)を指定する。
66
+ * キーの種類を示すオブジェクトを指定する。キーの種類には型
67
+ * 名("Int32"や"ShortText"など)またはGroonga::Typeまたは
68
+ * テーブル(Groonga::Array、Groonga::Hash、
69
+ * Groonga::PatriciaTrieのどれか)を指定する。
69
70
  *
70
71
  * Groonga::Typeを指定した場合は、その型が示す範囲の値をキー
71
72
  * として使用する。ただし、キーの最大サイズは4096バイトで
@@ -90,11 +91,11 @@ VALUE rb_cGrnHash;
90
91
  * Groonga::IndexColumnで使用するトークナイザを指定する。
91
92
  * デフォルトでは何も設定されていないので、テーブルに
92
93
  * Groonga::IndexColumnを定義する場合は
93
- * <tt>"<token:bigram>"</tt>などを指定する必要がある。
94
+ * <tt>"TokenBigram"</tt>などを指定する必要がある。
94
95
  *
95
96
  * [+:sub_records+]
96
97
  * +true+を指定すると#groupでグループ化したときに、
97
- * <tt>record[".:nsubrecs"]</tt>でグループに含まれるレコー
98
+ * Groonga::Record#n_sub_recordsでグループに含まれるレコー
98
99
  * ドの件数を取得できる。
99
100
  *
100
101
  * 使用例:
@@ -107,7 +108,7 @@ VALUE rb_cGrnHash;
107
108
  *
108
109
  * 名前付き永続テーブルを生成する。ただし、ファイル名は気に
109
110
  * しない。
110
- * Groonga::Hash.create(:name => "<bookmarks>",
111
+ * Groonga::Hash.create(:name => "Bookmarks",
111
112
  * :persistent => true)
112
113
  *
113
114
  * それぞれのレコードに512バイトの値を格納できる無名一時テー
@@ -115,34 +116,34 @@ VALUE rb_cGrnHash;
115
116
  * Groonga::Hash.create(:value => 512)
116
117
  *
117
118
  * キーとして文字列を使用する無名一時テーブルを生成する。
118
- * Groonga::Hash.create(:key_type => Groonga::Type::TEXT)
119
+ * Groonga::Hash.create(:key_type => Groonga::Type::SHORT_TEXT)
119
120
  *
120
121
  * キーとして文字列を使用する無名一時テーブルを生成する。
121
122
  * (キーの種類を表すオブジェクトは文字列で指定。)
122
- * Groonga::Hash.create(:key_type => "<shorttext>")
123
+ * Groonga::Hash.create(:key_type => "ShortText")
123
124
  *
124
- * キーとして<tt><bookmarks></tt>テーブルのレコードを使用す
125
+ * キーとして<tt>Bookmarks</tt>テーブルのレコードを使用す
125
126
  * る無名一時テーブルを生成する。
126
- * bookmarks = Groonga::Hash.create(:name => "<bookmarks>")
127
+ * bookmarks = Groonga::Hash.create(:name => "Bookmarks")
127
128
  * Groonga::Hash.create(:key_type => bookmarks)
128
129
  *
129
- * キーとして<tt><bookmarks></tt>テーブルのレコードを使用す
130
+ * キーとして<tt>Bookmarks</tt>テーブルのレコードを使用す
130
131
  * る無名一時テーブルを生成する。
131
132
  * (テーブルは文字列で指定。)
132
- * Groonga::Hash.create(:name => "<bookmarks>")
133
- * Groonga::Hash.create(:key_type => "<bookmarks>")
133
+ * Groonga::Hash.create(:name => "Bookmarks")
134
+ * Groonga::Hash.create(:key_type => "Bookmarks")
134
135
  *
135
136
  * 全文検索用のトークンをバイグラムで切り出す無名一時テーブ
136
137
  * ルを生成する。
137
- * bookmarks = Groonga::Hash.create(:name => "<bookmarks>")
138
- * bookmarks.define_column("comment", "<text>")
139
- * terms = Groonga::Hash.create(:name => "<terms>",
140
- * :default_tokenizer => "<token:bigram>")
138
+ * bookmarks = Groonga::Hash.create(:name => "Bookmarks")
139
+ * bookmarks.define_column("comment", "Text")
140
+ * terms = Groonga::Hash.create(:name => "Terms",
141
+ * :default_tokenizer => "TokenBigram")
141
142
  * terms.define_index_column("content", bookmarks,
142
- * :source => "<bookmarks>.comment")
143
+ * :source => "Bookmarks.comment")
143
144
  */
144
145
  static VALUE
145
- rb_grn_hash_s_create (int argc, VALUE *argv, VALUE self)
146
+ rb_grn_hash_s_create (int argc, VALUE *argv, VALUE klass)
146
147
  {
147
148
  grn_ctx *context;
148
149
  grn_obj *key_type = NULL, *value_type = NULL, *table;
@@ -199,9 +200,7 @@ rb_grn_hash_s_create (int argc, VALUE *argv, VALUE self)
199
200
  flags, key_type, value_type);
200
201
  if (!table)
201
202
  rb_grn_context_check(context, rb_ary_new4(argc, argv));
202
- rb_table = rb_grn_object_alloc(self);
203
- rb_grn_object_assign(Qnil, rb_table, rb_context, context, table);
204
- rb_grn_context_check(context, rb_table);
203
+ rb_table = GRNOBJECT2RVAL(klass, context, table, RB_GRN_TRUE);
205
204
 
206
205
  if (!NIL_P(rb_default_tokenizer))
207
206
  rb_funcall(rb_table, rb_intern("default_tokenizer="), 1,
@@ -219,7 +218,7 @@ rb_grn_hash_s_create (int argc, VALUE *argv, VALUE self)
219
218
  *
220
219
  * _key_にマッチするレコードのIDがキーに入っている
221
220
  * Groonga::Hashを返す。マッチするレコードがない場合は空の
222
- * Groonga::Hashが返。
221
+ * Groonga::Hashが返る。
223
222
  *
224
223
  * _options_で+:result+を指定することにより、そのテーブルにマッ
225
224
  * チしたレコードIDがキーのレコードを追加することができる。
@@ -253,7 +252,8 @@ rb_grn_hash_search (int argc, VALUE *argv, VALUE self)
253
252
 
254
253
  rb_grn_table_key_support_deconstruct(SELF(self), &table, &context,
255
254
  &key, &domain_id, &domain,
256
- NULL, NULL, NULL);
255
+ NULL, NULL, NULL,
256
+ NULL);
257
257
 
258
258
  rb_scan_args(argc, argv, "11", &rb_key, &options);
259
259
 
@@ -18,6 +18,8 @@
18
18
 
19
19
  #include "rb-grn.h"
20
20
 
21
+ #include <string.h>
22
+
21
23
  #define SELF(object) ((RbGrnIndexColumn *)DATA_PTR(object))
22
24
 
23
25
  VALUE rb_cGrnIndexColumn;
@@ -128,13 +130,13 @@ rb_grn_index_column_deconstruct (RbGrnIndexColumn *rb_grn_index_column,
128
130
  *
129
131
  * 記事の段落毎に索引を作成する。
130
132
  * articles = Groonga::Array.create(:name => "<articles>")
131
- * articles.define_column("title", "<shottext>")
132
- * articles.define_column("content", "<text>")
133
+ * articles.define_column("title", "ShortText")
134
+ * articles.define_column("content", "Text")
133
135
  *
134
136
  * terms = Groonga::Hash.create(:name => "<terms>",
135
- * :with_section => true,
136
- * :default_tokenizer => "<token:bigram>")
137
- * content_index = terms.define_index_column("content", articles)
137
+ * :default_tokenizer => "TokenBigram")
138
+ * content_index = terms.define_index_column("content", articles,
139
+ * :with_section => true)
138
140
  *
139
141
  * content = <<-EOC
140
142
  * groonga は組み込み型の全文検索エンジンライブラリです。
@@ -157,7 +159,7 @@ rb_grn_index_column_deconstruct (RbGrnIndexColumn *rb_grn_index_column,
157
159
  * content_index[groonga] = {:value => sentence, :section => i + 1}
158
160
  * end
159
161
  *
160
- * content.search("エンジン").collect do |record|
162
+ * content_index.search("エンジン").collect do |record|
161
163
  * p record.key["title"] # -> "groonga"
162
164
  * end
163
165
  */
@@ -222,6 +224,12 @@ rb_grn_index_column_array_set (VALUE self, VALUE rb_id, VALUE rb_value)
222
224
  return original_rb_value;
223
225
  }
224
226
 
227
+ /*
228
+ * call-seq:
229
+ * column.sources -> Groonga::Columnの配列
230
+ *
231
+ * インデックス対象となっているカラムの配列を返す。
232
+ */
225
233
  static VALUE
226
234
  rb_grn_index_column_get_sources (VALUE self)
227
235
  {
@@ -258,6 +266,59 @@ rb_grn_index_column_get_sources (VALUE self)
258
266
  return rb_sources;
259
267
  }
260
268
 
269
+ static grn_id
270
+ resolve_source_id (grn_ctx *context, grn_obj *column, VALUE rb_source)
271
+ {
272
+ grn_id source_id;
273
+
274
+ if (CBOOL2RVAL(rb_obj_is_kind_of(rb_source, rb_cInteger))) {
275
+ source_id = NUM2UINT(rb_source);
276
+ } else {
277
+ grn_obj *source;
278
+
279
+ if (TYPE(rb_source) == T_STRING) {
280
+ grn_obj *table;
281
+ const char *name;
282
+ const char *dot_point;
283
+ int length;
284
+
285
+ table = grn_ctx_at(context, grn_obj_get_range(context, column));
286
+ name = StringValueCStr(rb_source);
287
+ length = RSTRING_LEN(rb_source);
288
+ dot_point = strstr(name, ".");
289
+ if (dot_point) {
290
+ char table_name[4096];
291
+ int table_name_length;
292
+
293
+ table_name_length = grn_obj_name(context, table,
294
+ table_name, sizeof(table_name));
295
+ table_name[table_name_length] = '\0';
296
+ if (strncmp(table_name, name, dot_point - name) != 0) {
297
+ rb_raise(rb_eArgError,
298
+ "wrong table's column: <%s>: "
299
+ "expected table: <%s>",
300
+ name, table_name);
301
+ }
302
+ length -= (dot_point - name) + 1;
303
+ name = dot_point + 1;
304
+ }
305
+ source = grn_obj_column(context, table, name, length);
306
+ } else {
307
+ source = RVAL2GRNOBJECT(rb_source, &context);
308
+ }
309
+ rb_grn_context_check(context, rb_source);
310
+ source_id = grn_obj_id(context, source);
311
+ }
312
+
313
+ return source_id;
314
+ }
315
+
316
+ /*
317
+ * call-seq:
318
+ * column.sources = Groonga::Columnの配列
319
+ *
320
+ * インデックス対象となる複数のカラムを配列で設定する。
321
+ */
261
322
  static VALUE
262
323
  rb_grn_index_column_set_sources (VALUE self, VALUE rb_sources)
263
324
  {
@@ -278,19 +339,7 @@ rb_grn_index_column_set_sources (VALUE self, VALUE rb_sources)
278
339
  rb_source_values = RARRAY_PTR(rb_sources);
279
340
  sources = ALLOCA_N(grn_id, n);
280
341
  for (i = 0; i < n; i++) {
281
- VALUE rb_source_id;
282
- grn_obj *source;
283
- grn_id source_id;
284
-
285
- rb_source_id = rb_source_values[i];
286
- if (CBOOL2RVAL(rb_obj_is_kind_of(rb_source_id, rb_cInteger))) {
287
- source_id = NUM2UINT(rb_source_id);
288
- } else {
289
- source = RVAL2GRNOBJECT(rb_source_id, &context);
290
- rb_grn_context_check(context, rb_source_id);
291
- source_id = grn_obj_id(context, source);
292
- }
293
- sources[i] = source_id;
342
+ sources[i] = resolve_source_id(context, column, rb_source_values[i]);
294
343
  }
295
344
 
296
345
  {
@@ -309,6 +358,12 @@ rb_grn_index_column_set_sources (VALUE self, VALUE rb_sources)
309
358
  return Qnil;
310
359
  }
311
360
 
361
+ /*
362
+ * call-seq:
363
+ * column.source = Groonga::Column
364
+ *
365
+ * インデックス対象となるカラムを設定する。
366
+ */
312
367
  static VALUE
313
368
  rb_grn_index_column_set_source (VALUE self, VALUE rb_source)
314
369
  {
@@ -18,6 +18,13 @@
18
18
 
19
19
  #include "rb-grn.h"
20
20
 
21
+ /*
22
+ * Document-class: Groonga::Logger
23
+ *
24
+ * groongaから出力されるログを記録するためのクラス。
25
+ *
26
+ */
27
+
21
28
  #define RVAL2GRNWRAPPER(object) (rb_grn_logger_info_wrapper_from_ruby_object(object))
22
29
  #define RVAL2GRNLOGLEVEL(object) (rb_grn_log_level_from_ruby_object(object))
23
30
  #define GRNLOGLEVEL2RVAL(level) (rb_grn_log_level_to_ruby_object(level))
@@ -235,6 +242,47 @@ rb_grn_logger_initialize (int argc, VALUE *argv, VALUE self)
235
242
  return Qnil;
236
243
  }
237
244
 
245
+ /*
246
+ * call-seq:
247
+ * Groonga::Logger.register(options={})
248
+ {|level, time, title, message, location| ...}
249
+ *
250
+ * groongaがログを出力する度に呼び出されるブロックを登録す
251
+ * る。
252
+ *
253
+ * ブロックに渡されてくる引数は_level_, _time_, _title_,
254
+ * _message_, _location_の5つで、_level_はSymbol、それ以外は
255
+ * 全て文字列で渡される。その4つについては_options_で+false+
256
+ * を指定することでブロックに渡さないようにすることができ、
257
+ * その場合は空文字列が実際には渡される。
258
+ *
259
+ * _options_に指定可能な値は以下の通り。
260
+ *
261
+ * [+:level+]
262
+ * ログのレベルを+:none+, +:emergency+, +:alert+,
263
+ * +:critical+, +:error+, +:warning+, +:notice+, +:info+,
264
+ * +:debug+, +:dump+のいずれかで指定する。それより重要度が
265
+ * 低いログはブロックに渡されなくなる。デフォルトでは
266
+ * +:notice+。
267
+ *
268
+ * [+:time+]
269
+ * ログが出力された時間をブロックに渡したいなら+true+を指
270
+ * 定する。デフォルトでは渡す。
271
+ *
272
+ * [+:title+]
273
+ * ログのタイトルをブロックに渡したいなら+true+を指定す
274
+ * る。デフォルトでは渡す。(FIXME: groongaで実装されてい
275
+ * ない?)
276
+ *
277
+ * [+:message+]
278
+ * ログのメッセージをブロックに渡したいなら+true+を指定す
279
+ * る。デフォルトでは渡す。
280
+ *
281
+ * [+:location+]
282
+ * ログの発生元のプロセスIDとgroongaのソースコードのファイ
283
+ * ル名、行番号、関数名をブロックに渡したいなら+true+を指
284
+ * 定する。デフォルトでは渡す。
285
+ */
238
286
  static VALUE
239
287
  rb_grn_logger_s_register (int argc, VALUE *argv, VALUE klass)
240
288
  {
@@ -1,6 +1,6 @@
1
1
  /* -*- c-file-style: "ruby" -*- */
2
2
  /*
3
- Copyright (C) 2009 Kouhei Sutou <kou@clear-code.com>
3
+ Copyright (C) 2009-2010 Kouhei Sutou <kou@clear-code.com>
4
4
 
5
5
  This library is free software; you can redistribute it and/or
6
6
  modify it under the terms of the GNU Lesser General Public
@@ -65,7 +65,8 @@ rb_grn_object_from_ruby_object (VALUE object, grn_ctx **context)
65
65
  }
66
66
 
67
67
  if (!RVAL2CBOOL(rb_obj_is_kind_of(object, rb_cGrnObject))) {
68
- rb_raise(rb_eTypeError, "not a groonga object");
68
+ rb_raise(rb_eTypeError, "not a groonga object: <%s>",
69
+ rb_grn_inspect(object));
69
70
  }
70
71
 
71
72
  Data_Get_Struct(object, RbGrnObject, rb_grn_object);
@@ -93,10 +94,10 @@ rb_grn_object_finalizer (grn_ctx *context, int n_args, grn_obj **grn_objects,
93
94
  grn_obj_user_data(context, grn_object)->ptr = NULL;
94
95
  grn_obj_set_finalizer(context, grn_object, NULL);
95
96
 
96
- debug("finalize %p:%p:%p:%p:%p %x\n",
97
- context, grn_object, rb_grn_object,
98
- rb_grn_object->context, rb_grn_object->object,
99
- grn_object->header.type);
97
+ debug("finalize: %p:%p:%p:%p:%p 0x%x\n",
98
+ context, grn_object, rb_grn_object,
99
+ rb_grn_object->context, rb_grn_object->object,
100
+ grn_object->header.type);
100
101
 
101
102
  rb_grn_object->context = NULL;
102
103
  rb_grn_object->object = NULL;
@@ -106,7 +107,6 @@ rb_grn_object_finalizer (grn_ctx *context, int n_args, grn_obj **grn_objects,
106
107
  grn_ctx_use(context, NULL);
107
108
  break;
108
109
  case GRN_TYPE:
109
- case GRN_ACCESSOR:
110
110
  case GRN_PROC:
111
111
  case GRN_CURSOR_TABLE_HASH_KEY:
112
112
  case GRN_CURSOR_TABLE_PAT_KEY:
@@ -130,6 +130,10 @@ rb_grn_object_finalizer (grn_ctx *context, int n_args, grn_obj **grn_objects,
130
130
  rb_grn_index_column_finalizer(context, grn_object,
131
131
  RB_GRN_INDEX_COLUMN(rb_grn_object));
132
132
  break;
133
+ case GRN_ACCESSOR:
134
+ rb_grn_named_object_finalizer(context, grn_object,
135
+ RB_GRN_NAMED_OBJECT(rb_grn_object));
136
+ break;
133
137
  case GRN_EXPR:
134
138
  rb_grn_expression_finalizer(context, grn_object,
135
139
  RB_GRN_EXPRESSION(rb_grn_object));
@@ -226,21 +230,26 @@ VALUE
226
230
  rb_grn_object_to_ruby_object (VALUE klass, grn_ctx *context, grn_obj *object,
227
231
  rb_grn_boolean owner)
228
232
  {
229
- VALUE rb_object;
233
+ RbGrnContext *rb_grn_context;
234
+ VALUE rb_object, rb_context = Qnil;
230
235
  grn_user_data *user_data;
231
236
 
232
237
  if (!object)
233
238
  return Qnil;
234
239
 
235
240
  user_data = grn_obj_user_data(context, object);
236
- if (user_data && user_data->ptr)
241
+ if (user_data && user_data->ptr) {
237
242
  return RB_GRN_OBJECT(user_data->ptr)->self;
243
+ }
238
244
 
239
245
  if (NIL_P(klass))
240
246
  klass = GRNOBJECT2RCLASS(object);
241
247
 
248
+ rb_grn_context = GRN_CTX_USER_DATA(context)->ptr;
249
+ if (rb_grn_context)
250
+ rb_context = rb_grn_context->self;
242
251
  rb_object = rb_obj_alloc(klass);
243
- rb_grn_object_assign(klass, rb_object, Qnil, context, object);
252
+ rb_grn_object_assign(klass, rb_object, rb_context, context, object);
244
253
 
245
254
  return rb_object;
246
255
  }
@@ -256,11 +265,11 @@ rb_grn_object_bind_common (VALUE klass, VALUE self, VALUE rb_context,
256
265
  RbGrnObject *rb_grn_object,
257
266
  grn_ctx *context, grn_obj *object)
258
267
  {
259
- DATA_PTR(self) = rb_grn_object;
260
- rb_iv_set(self, "context", rb_context);
261
-
268
+ rb_grn_object->context = context;
269
+ rb_grn_object->object = object;
262
270
  rb_grn_object->self = self;
263
271
  rb_grn_object->need_close = RB_GRN_TRUE;
272
+
264
273
  switch (object->header.type) {
265
274
  case GRN_DB:
266
275
  case GRN_CURSOR_TABLE_HASH_KEY:
@@ -286,9 +295,6 @@ rb_grn_object_bind_common (VALUE klass, VALUE self, VALUE rb_context,
286
295
  break;
287
296
  }
288
297
 
289
- rb_grn_object->context = context;
290
- rb_grn_object->object = object;
291
-
292
298
  rb_grn_object->domain_id = GRN_ID_NIL;
293
299
  if (object)
294
300
  rb_grn_object->domain_id = object->header.domain;
@@ -304,6 +310,9 @@ rb_grn_object_bind_common (VALUE klass, VALUE self, VALUE rb_context,
304
310
  rb_grn_object->range = NULL;
305
311
  else
306
312
  rb_grn_object->range = grn_ctx_at(context, rb_grn_object->range_id);
313
+
314
+ DATA_PTR(self) = rb_grn_object;
315
+ rb_iv_set(self, "@context", rb_context);
307
316
  }
308
317
 
309
318
  void
@@ -323,7 +332,6 @@ rb_grn_object_assign (VALUE klass, VALUE self, VALUE rb_context,
323
332
  klass == rb_cGrnHashCursor ||
324
333
  klass == rb_cGrnPatriciaTrieCursor ||
325
334
  klass == rb_cGrnArrayCursor ||
326
- klass == rb_cGrnAccessor ||
327
335
  klass == rb_cGrnProcedure ||
328
336
  klass == rb_cGrnVariable) {
329
337
  rb_grn_object = ALLOC(RbGrnObject);
@@ -351,6 +359,12 @@ rb_grn_object_assign (VALUE klass, VALUE self, VALUE rb_context,
351
359
  rb_grn_object_bind_common(klass, self, rb_context, rb_grn_object,
352
360
  context, object);
353
361
  rb_grn_column_bind(RB_GRN_COLUMN(rb_grn_object), context, object);
362
+ } else if (klass == rb_cGrnAccessor) {
363
+ rb_grn_object = ALLOC(RbGrnNamedObject);
364
+ rb_grn_object_bind_common(klass, self, rb_context, rb_grn_object,
365
+ context, object);
366
+ rb_grn_named_object_bind(RB_GRN_NAMED_OBJECT(rb_grn_object),
367
+ context, object);
354
368
  } else if (klass == rb_cGrnExpression) {
355
369
  rb_grn_object = ALLOC(RbGrnExpression);
356
370
  rb_grn_object_bind_common(klass, self, rb_context, rb_grn_object,
@@ -367,6 +381,43 @@ rb_grn_object_assign (VALUE klass, VALUE self, VALUE rb_context,
367
381
  object->header.type);
368
382
  }
369
383
 
384
+ void
385
+ rb_grn_named_object_bind (RbGrnNamedObject *rb_grn_named_object,
386
+ grn_ctx *context, grn_obj *object)
387
+ {
388
+ RbGrnObject *rb_grn_object;
389
+
390
+ rb_grn_object = RB_GRN_OBJECT(rb_grn_named_object);
391
+
392
+ rb_grn_named_object->name = NULL;
393
+ rb_grn_named_object->name_size = 0;
394
+ }
395
+
396
+ void
397
+ rb_grn_named_object_finalizer (grn_ctx *context, grn_obj *grn_object,
398
+ RbGrnNamedObject *rb_grn_named_object)
399
+ {
400
+ if (rb_grn_named_object->name)
401
+ free(rb_grn_named_object->name);
402
+ rb_grn_named_object->name = NULL;
403
+ rb_grn_named_object->name_size = 0;
404
+ }
405
+
406
+ void
407
+ rb_grn_named_object_set_name (RbGrnNamedObject *rb_grn_named_object,
408
+ const char *name, unsigned name_size)
409
+ {
410
+ if (rb_grn_named_object->name) {
411
+ free(rb_grn_named_object->name);
412
+ rb_grn_named_object->name = NULL;
413
+ }
414
+ if (name_size > 0) {
415
+ rb_grn_named_object->name = strndup(name, name_size);
416
+ }
417
+ rb_grn_named_object->name_size = name_size;
418
+ }
419
+
420
+
370
421
  void
371
422
  rb_grn_object_deconstruct (RbGrnObject *rb_grn_object,
372
423
  grn_obj **object,
@@ -379,6 +430,12 @@ rb_grn_object_deconstruct (RbGrnObject *rb_grn_object,
379
430
  if (!rb_grn_object)
380
431
  return;
381
432
 
433
+ if (!rb_grn_object->object) {
434
+ rb_raise(rb_eGrnObjectClosed,
435
+ "can't access already closed groonga object: %s",
436
+ rb_grn_inspect(CLASS_OF(rb_grn_object->self)));
437
+ }
438
+
382
439
  if (object)
383
440
  *object = rb_grn_object->object;
384
441
  if (context)
@@ -427,15 +484,14 @@ rb_grn_object_close (VALUE self)
427
484
  VALUE
428
485
  rb_grn_object_closed_p (VALUE self)
429
486
  {
430
- grn_obj *object;
431
- grn_ctx *context;
487
+ RbGrnObject *rb_grn_object;
432
488
 
433
- rb_grn_object_deconstruct(SELF(self), &object, &context,
434
- NULL, NULL, NULL, NULL);
435
- if (context && object)
489
+ rb_grn_object = SELF(self);
490
+ if (rb_grn_object->context && rb_grn_object->object) {
436
491
  return Qfalse;
437
- else
492
+ } else {
438
493
  return Qtrue;
494
+ }
439
495
  }
440
496
 
441
497
  VALUE
@@ -459,8 +515,8 @@ rb_grn_object_inspect_header (VALUE self, VALUE inspected)
459
515
  }
460
516
 
461
517
  static VALUE
462
- rb_grn_object_inspect_content_id (VALUE inspected,
463
- grn_ctx *context, grn_obj *object)
518
+ rb_grn_object_inspect_content_id_with_label (VALUE inspected,
519
+ grn_ctx *context, grn_obj *object)
464
520
  {
465
521
  grn_id id;
466
522
 
@@ -481,7 +537,6 @@ rb_grn_object_inspect_content_name (VALUE inspected,
481
537
  {
482
538
  int name_size;
483
539
 
484
- rb_str_cat2(inspected, "name: ");
485
540
  name_size = grn_obj_name(context, object, NULL, 0);
486
541
  if (name_size == 0) {
487
542
  rb_str_cat2(inspected, "(anonymous)");
@@ -502,8 +557,18 @@ rb_grn_object_inspect_content_name (VALUE inspected,
502
557
  }
503
558
 
504
559
  static VALUE
505
- rb_grn_object_inspect_content_path (VALUE inspected,
506
- grn_ctx *context, grn_obj *object)
560
+ rb_grn_object_inspect_content_name_with_label (VALUE inspected,
561
+ grn_ctx *context, grn_obj *object)
562
+ {
563
+
564
+ rb_str_cat2(inspected, "name: ");
565
+ rb_grn_object_inspect_content_name(inspected, context, object);
566
+ return inspected;
567
+ }
568
+
569
+ static VALUE
570
+ rb_grn_object_inspect_content_path_with_label (VALUE inspected,
571
+ grn_ctx *context, grn_obj *object)
507
572
  {
508
573
  const char *path;
509
574
 
@@ -521,71 +586,82 @@ rb_grn_object_inspect_content_path (VALUE inspected,
521
586
  }
522
587
 
523
588
  static VALUE
524
- rb_grn_object_inspect_content_domain (VALUE inspected,
525
- grn_ctx *context, grn_obj *object)
589
+ rb_grn_object_inspect_content_domain_with_label (VALUE inspected,
590
+ grn_ctx *context,
591
+ grn_obj *object)
526
592
  {
527
593
  grn_id domain;
528
594
 
529
595
  rb_str_cat2(inspected, "domain: ");
530
596
  domain = object->header.domain;
531
- rb_str_cat2(inspected, "<");
532
597
  if (domain == GRN_ID_NIL) {
533
- rb_str_cat2(inspected, "nil");
598
+ rb_str_cat2(inspected, "(nil)");
534
599
  } else {
535
600
  grn_obj *domain_object;
536
601
 
537
602
  domain_object = grn_ctx_at(context, domain);
538
603
  if (domain_object) {
539
604
  if (domain_object == object) {
540
- rb_str_cat2(inspected, "self");
605
+ rb_str_cat2(inspected, "(self)");
541
606
  } else {
542
- rb_grn_object_inspect_object(inspected, context, domain_object);
607
+ rb_grn_object_inspect_content_name(inspected,
608
+ context, domain_object);
543
609
  }
544
610
  } else {
611
+ rb_str_cat2(inspected, "(");
545
612
  rb_str_concat(inspected, rb_obj_as_string(UINT2NUM(domain)));
613
+ rb_str_cat2(inspected, ")");
546
614
  }
547
615
  }
548
- rb_str_cat2(inspected, ">");
549
616
 
550
617
  return inspected;
551
618
  }
552
619
 
553
620
  static VALUE
554
- rb_grn_object_inspect_content_range (VALUE inspected,
555
- grn_ctx *context, grn_obj *object)
621
+ rb_grn_object_inspect_content_range_with_label (VALUE inspected,
622
+ grn_ctx *context,
623
+ grn_obj *object)
556
624
  {
557
625
  grn_id range;
558
626
 
559
627
  rb_str_cat2(inspected, "range: ");
560
628
 
561
629
  range = grn_obj_get_range(context, object);
562
- rb_str_cat2(inspected, "<");
563
630
  switch (object->header.type) {
564
631
  case GRN_TYPE:
632
+ rb_str_cat2(inspected, "<");
565
633
  rb_str_concat(inspected, rb_inspect(UINT2NUM(range)));
634
+ rb_str_cat2(inspected, ">");
566
635
  break;
567
636
  default:
568
637
  if (range == GRN_ID_NIL) {
569
- rb_str_cat2(inspected, "nil");
638
+ rb_str_cat2(inspected, "(nil)");
570
639
  } else {
571
640
  grn_obj *range_object;
572
641
 
573
642
  range_object = grn_ctx_at(context, range);
574
643
  if (range_object) {
575
- rb_grn_object_inspect_object(inspected, context, range_object);
644
+ if (range_object == object) {
645
+ rb_str_cat2(inspected, "(self)");
646
+ } else {
647
+ rb_grn_object_inspect_content_name(inspected,
648
+ context, range_object);
649
+ }
576
650
  } else {
651
+ rb_str_cat2(inspected, "(");
577
652
  rb_str_concat(inspected, rb_obj_as_string(UINT2NUM(range)));
653
+ rb_str_cat2(inspected, ")");
578
654
  }
579
655
  }
580
656
  }
581
- rb_str_cat2(inspected, ">");
582
657
 
583
658
  return inspected;
584
659
  }
585
660
 
586
661
  static VALUE
587
- rb_grn_object_inspect_content_flags (VALUE inspected,
588
- grn_ctx *context, grn_obj *object)
662
+ rb_grn_object_inspect_content_flags_with_label (VALUE inspected,
663
+ grn_ctx *context,
664
+ grn_obj *object)
589
665
  {
590
666
  grn_obj_flags flags;
591
667
  VALUE inspected_flags;
@@ -693,17 +769,17 @@ VALUE
693
769
  rb_grn_object_inspect_object_content (VALUE inspected,
694
770
  grn_ctx *context, grn_obj *object)
695
771
  {
696
- rb_grn_object_inspect_content_id(inspected, context, object);
772
+ rb_grn_object_inspect_content_id_with_label(inspected, context, object);
697
773
  rb_str_cat2(inspected, ", ");
698
- rb_grn_object_inspect_content_name(inspected, context, object);
774
+ rb_grn_object_inspect_content_name_with_label(inspected, context, object);
699
775
  rb_str_cat2(inspected, ", ");
700
- rb_grn_object_inspect_content_path(inspected, context, object);
776
+ rb_grn_object_inspect_content_path_with_label(inspected, context, object);
701
777
  rb_str_cat2(inspected, ", ");
702
- rb_grn_object_inspect_content_domain(inspected, context, object);
778
+ rb_grn_object_inspect_content_domain_with_label(inspected, context, object);
703
779
  rb_str_cat2(inspected, ", ");
704
- rb_grn_object_inspect_content_range(inspected, context, object);
780
+ rb_grn_object_inspect_content_range_with_label(inspected, context, object);
705
781
  rb_str_cat2(inspected, ", ");
706
- rb_grn_object_inspect_content_flags(inspected, context, object);
782
+ rb_grn_object_inspect_content_flags_with_label(inspected, context, object);
707
783
 
708
784
  return inspected;
709
785
  }
@@ -770,7 +846,7 @@ rb_grn_object_inspect (VALUE self)
770
846
  * _object_のIDを返す。_object_が#closed?なときやIDがない場合
771
847
  * は+nil+を返す。
772
848
  */
773
- static VALUE
849
+ VALUE
774
850
  rb_grn_object_get_id (VALUE self)
775
851
  {
776
852
  RbGrnObject *rb_grn_object;
@@ -787,6 +863,75 @@ rb_grn_object_get_id (VALUE self)
787
863
  return UINT2NUM(id);
788
864
  }
789
865
 
866
+ /*
867
+ * Document-method: path
868
+ *
869
+ * call-seq:
870
+ * object.path -> ファイルパス/nil
871
+ *
872
+ * _object_に対応するファイルパスを返す。一時_object_
873
+ * なら+nil+を返す。
874
+ */
875
+ static VALUE
876
+ rb_grn_object_get_path (VALUE self)
877
+ {
878
+ RbGrnObject *rb_grn_object;
879
+ const char *path;
880
+
881
+ rb_grn_object = SELF(self);
882
+ if (!rb_grn_object->object)
883
+ return Qnil;
884
+
885
+ path = grn_obj_path(rb_grn_object->context, rb_grn_object->object);
886
+
887
+ if (!path)
888
+ return Qnil;
889
+ else
890
+ return rb_str_new2(path);
891
+ }
892
+
893
+ /*
894
+ * Document-method: temporary?
895
+ *
896
+ * call-seq:
897
+ * object.temporary? -> true/false
898
+ *
899
+ * _object_が一時オブジェクトなら+true+、永続オブジェクトな
900
+ * ら+false+を返す。
901
+ */
902
+ static VALUE
903
+ rb_grn_object_temporary_p (VALUE self)
904
+ {
905
+ RbGrnObject *rb_grn_object;
906
+
907
+ rb_grn_object = SELF(self);
908
+ if (!rb_grn_object->object)
909
+ return Qnil;
910
+
911
+ return !(rb_grn_object->object->header.flags & GRN_OBJ_PERSISTENT);
912
+ }
913
+
914
+ /*
915
+ * Document-method: persistent?
916
+ *
917
+ * call-seq:
918
+ * object.persistent? -> true/false
919
+ *
920
+ * _object_が永続オブジェクトなら+true+、一時オブジェクトな
921
+ * ら+false+を返す。
922
+ */
923
+ static VALUE
924
+ rb_grn_object_persistent_p (VALUE self)
925
+ {
926
+ RbGrnObject *rb_grn_object;
927
+
928
+ rb_grn_object = SELF(self);
929
+ if (!rb_grn_object->object)
930
+ return Qnil;
931
+
932
+ return rb_grn_object->object->header.flags & GRN_OBJ_PERSISTENT;
933
+ }
934
+
790
935
  /*
791
936
  * Document-method: domain
792
937
  *
@@ -970,7 +1115,6 @@ rb_grn_object_array_reference (VALUE self, VALUE rb_id)
970
1115
  case GRN_OBJ_COLUMN_VECTOR:
971
1116
  GRN_OBJ_INIT(&value, GRN_VECTOR, 0, range_id);
972
1117
  break;
973
- case GRN_OBJ_COLUMN_INDEX:
974
1118
  case GRN_OBJ_COLUMN_SCALAR:
975
1119
  GRN_OBJ_INIT(&value, GRN_BULK, 0, range_id);
976
1120
  break;
@@ -980,6 +1124,9 @@ rb_grn_object_array_reference (VALUE self, VALUE rb_id)
980
1124
  break;
981
1125
  }
982
1126
  break;
1127
+ case GRN_COLUMN_INDEX:
1128
+ GRN_UINT32_INIT(&value, 0);
1129
+ break;
983
1130
  default:
984
1131
  rb_raise(rb_eGrnError,
985
1132
  "unsupported type: %s", rb_grn_inspect(self));
@@ -997,40 +1144,91 @@ rb_grn_object_array_reference (VALUE self, VALUE rb_id)
997
1144
  return rb_value;
998
1145
  }
999
1146
 
1000
- static VALUE
1001
- rb_grn_object_set (VALUE self, VALUE rb_id, VALUE rb_value, int flags)
1147
+ static rb_grn_boolean
1148
+ rb_uvector_value_p (RbGrnObject *rb_grn_object, VALUE rb_value)
1149
+ {
1150
+ VALUE first_element;
1151
+
1152
+ switch (rb_grn_object->range->header.type) {
1153
+ case GRN_TYPE:
1154
+ /* TODO: support not sizeof(grn_id) uvector. */
1155
+ /*
1156
+ if (!(rb_grn_object->range->header.flags | GRN_OBJ_KEY_VAR_SIZE)) {
1157
+ return RB_GRN_TRUE;
1158
+ }
1159
+ */
1160
+ break;
1161
+ case GRN_TABLE_HASH_KEY:
1162
+ case GRN_TABLE_PAT_KEY:
1163
+ case GRN_TABLE_NO_KEY:
1164
+ case GRN_TABLE_VIEW:
1165
+ first_element = rb_ary_entry(rb_value, 0);
1166
+ if (RVAL2CBOOL(rb_obj_is_kind_of(first_element, rb_cGrnRecord))) {
1167
+ return RB_GRN_TRUE;
1168
+ }
1169
+ break;
1170
+ default:
1171
+ break;
1172
+ }
1173
+
1174
+ return RB_GRN_FALSE;
1175
+ }
1176
+
1177
+ VALUE
1178
+ rb_grn_object_set_raw (RbGrnObject *rb_grn_object, grn_id id,
1179
+ VALUE rb_value, int flags, VALUE related_object)
1002
1180
  {
1003
- RbGrnObject *rb_grn_object;
1004
1181
  grn_ctx *context;
1005
- grn_id id;
1006
1182
  grn_obj value;
1007
1183
  grn_rc rc;
1008
1184
  VALUE exception;
1009
1185
 
1010
- rb_grn_object = SELF(self);
1011
- if (!rb_grn_object->object)
1012
- return Qnil;
1013
-
1014
1186
  context = rb_grn_object->context;
1015
- id = NUM2UINT(rb_id);
1016
1187
  if (RVAL2CBOOL(rb_obj_is_kind_of(rb_value, rb_cArray))) {
1017
- GRN_OBJ_INIT(&value, GRN_VECTOR, 0, GRN_ID_NIL);
1018
- RVAL2GRNVECTOR(rb_value, context, &value);
1188
+ if (rb_uvector_value_p(rb_grn_object, rb_value)) {
1189
+ GRN_OBJ_INIT(&value, GRN_UVECTOR, 0,
1190
+ rb_grn_object->object->header.domain);
1191
+ RVAL2GRNUVECTOR(rb_value, context, &value, related_object);
1192
+ } else {
1193
+ GRN_OBJ_INIT(&value, GRN_VECTOR, 0, GRN_ID_NIL);
1194
+ RVAL2GRNVECTOR(rb_value, context, &value);
1195
+ }
1019
1196
  } else {
1020
- GRN_OBJ_INIT(&value, GRN_BULK, 0, GRN_ID_NIL);
1021
- RVAL2GRNBULK(rb_value, context, &value);
1197
+ if (NIL_P(rb_value)) {
1198
+ GRN_OBJ_INIT(&value, GRN_BULK, 0, GRN_ID_NIL);
1199
+ } else {
1200
+ GRN_OBJ_INIT(&value, GRN_BULK, 0, GRN_ID_NIL);
1201
+ RVAL2GRNBULK(rb_value, context, &value);
1202
+ }
1022
1203
  }
1023
1204
  rc = grn_obj_set_value(context, rb_grn_object->object, id,
1024
1205
  &value, flags);
1025
- exception = rb_grn_context_to_exception(context, self);
1206
+ exception = rb_grn_context_to_exception(context, related_object);
1026
1207
  grn_obj_close(context, &value);
1027
1208
  if (!NIL_P(exception))
1028
1209
  rb_exc_raise(exception);
1029
- rb_grn_rc_check(rc, self);
1210
+ rb_grn_rc_check(rc, related_object);
1030
1211
 
1031
1212
  return Qnil;
1032
1213
  }
1033
1214
 
1215
+ static VALUE
1216
+ rb_grn_object_set (VALUE self, VALUE rb_id, VALUE rb_value, int flags)
1217
+ {
1218
+ RbGrnObject *rb_grn_object;
1219
+ grn_ctx *context;
1220
+ grn_id id;
1221
+
1222
+ rb_grn_object = SELF(self);
1223
+ if (!rb_grn_object->object)
1224
+ return Qnil;
1225
+
1226
+ context = rb_grn_object->context;
1227
+ id = NUM2UINT(rb_id);
1228
+
1229
+ return rb_grn_object_set_raw(rb_grn_object, id, rb_value, flags, self);
1230
+ }
1231
+
1034
1232
  /*
1035
1233
  * Document-method: []=
1036
1234
  *
@@ -1074,6 +1272,15 @@ rb_grn_object_prepend_value (VALUE self, VALUE rb_id, VALUE rb_value)
1074
1272
  return rb_grn_object_set(self, rb_id, rb_value, GRN_OBJ_PREPEND);
1075
1273
  }
1076
1274
 
1275
+ /*
1276
+ * Document-method: remove
1277
+ *
1278
+ * call-seq:
1279
+ * object.remove
1280
+ *
1281
+ * _object_をメモリから解放し、それが永続オブジェクトであっ
1282
+ * た場合は、該当するファイル一式を削除する。
1283
+ */
1077
1284
  static VALUE
1078
1285
  rb_grn_object_remove (VALUE self)
1079
1286
  {
@@ -1089,7 +1296,7 @@ rb_grn_object_remove (VALUE self)
1089
1296
  rc = grn_obj_remove(context, rb_grn_object->object);
1090
1297
  rb_grn_rc_check(rc, self);
1091
1298
 
1092
- rb_iv_set(self, "context", Qnil);
1299
+ rb_iv_set(self, "@context", Qnil);
1093
1300
 
1094
1301
  return Qnil;
1095
1302
  }
@@ -1100,12 +1307,19 @@ rb_grn_init_object (VALUE mGrn)
1100
1307
  rb_cGrnObject = rb_define_class_under(mGrn, "Object", rb_cObject);
1101
1308
  rb_define_alloc_func(rb_cGrnObject, rb_grn_object_alloc);
1102
1309
 
1310
+ rb_define_attr(rb_cGrnObject, "context", RB_GRN_TRUE, RB_GRN_FALSE);
1311
+
1103
1312
  rb_define_method(rb_cGrnObject, "inspect", rb_grn_object_inspect, 0);
1104
1313
 
1105
1314
  rb_define_method(rb_cGrnObject, "id", rb_grn_object_get_id, 0);
1106
1315
  rb_define_method(rb_cGrnObject, "domain", rb_grn_object_get_domain, 0);
1107
1316
  rb_define_method(rb_cGrnObject, "name", rb_grn_object_get_name, 0);
1108
1317
  rb_define_method(rb_cGrnObject, "range", rb_grn_object_get_range, 0);
1318
+ rb_define_method(rb_cGrnObject, "path", rb_grn_object_get_path, 0);
1319
+
1320
+ rb_define_method(rb_cGrnObject, "temporary?", rb_grn_object_temporary_p, 0);
1321
+ rb_define_method(rb_cGrnObject, "persistent?",
1322
+ rb_grn_object_persistent_p, 0);
1109
1323
 
1110
1324
  rb_define_method(rb_cGrnObject, "==", rb_grn_object_equal, 1);
1111
1325