groonga 0.0.7 → 0.9.0

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