rroonga 2.0.6 → 2.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.
data/Rakefile CHANGED
@@ -44,6 +44,10 @@ $LOAD_PATH.unshift(groonga_lib_dir)
44
44
  ENV["RUBYLIB"] = "#{groonga_lib_dir}:#{groonga_ext_dir}:#{ENV['RUBYLIB']}"
45
45
 
46
46
  helper = Bundler::GemHelper.new(base_dir)
47
+ def helper.version_tag
48
+ version
49
+ end
50
+
47
51
  helper.install
48
52
  spec = helper.gemspec
49
53
 
@@ -64,7 +64,7 @@ rb_grn_index_column_bind (RbGrnIndexColumn *rb_grn_index_column,
64
64
  rb_grn_object->domain_id);
65
65
  rb_grn_index_column->string_query = grn_obj_open(context, GRN_BULK,
66
66
  GRN_OBJ_DO_SHALLOW_COPY,
67
- GRN_ID_NIL);
67
+ GRN_DB_SHORT_TEXT);
68
68
  }
69
69
 
70
70
  void
@@ -540,23 +540,29 @@ rb_grn_index_column_open_cursor (VALUE self, VALUE rb_table_cursor)
540
540
  {
541
541
  grn_ctx *context;
542
542
  grn_obj *column;
543
+ grn_obj *range_object;
543
544
  grn_table_cursor *table_cursor;
544
545
  grn_id rid_min = GRN_ID_NIL;
545
546
  grn_id rid_max = GRN_ID_MAX;
546
547
  int flags = 0;
547
548
  grn_obj *index_cursor;
549
+ VALUE rb_table;
550
+ VALUE rb_lexicon;
548
551
  VALUE rb_cursor;
549
552
 
550
553
  rb_grn_index_column_deconstruct(SELF(self), &column, &context,
551
554
  NULL, NULL,
552
- NULL, NULL, NULL, NULL,
555
+ NULL, NULL,
556
+ NULL, &range_object,
553
557
  NULL, NULL);
554
558
  table_cursor = RVAL2GRNTABLECURSOR(rb_table_cursor, NULL);
559
+ rb_table = GRNOBJECT2RVAL(Qnil, context, range_object, GRN_FALSE);
560
+ rb_lexicon = rb_iv_get(rb_table_cursor, "@table");
555
561
 
556
562
  index_cursor = grn_index_cursor_open(context, table_cursor,
557
563
  column, rid_min, rid_max, flags);
558
564
 
559
- rb_cursor = GRNINDEXCURSOR2RVAL(context, index_cursor);
565
+ rb_cursor = GRNINDEXCURSOR2RVAL(context, index_cursor, rb_table, rb_lexicon);
560
566
 
561
567
  if (rb_block_given_p())
562
568
  return rb_ensure(rb_yield, rb_cursor, rb_grn_object_close, rb_cursor);
@@ -26,9 +26,17 @@ VALUE rb_cGrnIndexCursor;
26
26
  VALUE
27
27
  rb_grn_index_cursor_to_ruby_object (grn_ctx *context,
28
28
  grn_obj *cursor,
29
+ VALUE rb_table,
30
+ VALUE rb_lexicon,
29
31
  grn_bool owner)
30
32
  {
31
- return GRNOBJECT2RVAL(rb_cGrnIndexCursor, context, cursor, owner);
33
+ VALUE rb_cursor;
34
+
35
+ rb_cursor = GRNOBJECT2RVAL(rb_cGrnIndexCursor, context, cursor, owner);
36
+ rb_iv_set(rb_cursor, "@table", rb_table);
37
+ rb_iv_set(rb_cursor, "@lexicon", rb_lexicon);
38
+
39
+ return rb_cursor;
32
40
  }
33
41
 
34
42
  void
@@ -48,6 +56,20 @@ rb_grn_index_cursor_deconstruct (RbGrnIndexCursor *rb_grn_index_cursor,
48
56
  range_id, range);
49
57
  }
50
58
 
59
+ static VALUE
60
+ next_value (grn_ctx *context, grn_obj *cursor, VALUE rb_table, VALUE rb_lexicon)
61
+ {
62
+ grn_posting *posting;
63
+ grn_id term_id;
64
+
65
+ posting = grn_index_cursor_next(context, cursor, &term_id);
66
+ if (!posting) {
67
+ return Qnil;
68
+ }
69
+
70
+ return rb_grn_posting_new(posting, term_id, rb_table, rb_lexicon);
71
+ }
72
+
51
73
  static VALUE
52
74
  rb_grn_index_cursor_next (VALUE self)
53
75
  {
@@ -57,16 +79,12 @@ rb_grn_index_cursor_next (VALUE self)
57
79
 
58
80
  rb_grn_index_cursor_deconstruct(SELF(self), &cursor, &context,
59
81
  NULL, NULL, NULL, NULL);
60
-
61
82
  if (context && cursor) {
62
- grn_posting *posting;
63
- grn_id tid;
64
-
65
- posting = grn_index_cursor_next(context, cursor, &tid);
66
-
67
- if (posting) {
68
- rb_posting = rb_grn_posting_new(posting, tid);
69
- }
83
+ VALUE rb_table;
84
+ VALUE rb_lexicon;
85
+ rb_table = rb_iv_get(self, "@table");
86
+ rb_lexicon = rb_iv_get(self, "@lexicon");
87
+ rb_posting = next_value(context, cursor, rb_table, rb_lexicon);
70
88
  }
71
89
 
72
90
  return rb_posting;
@@ -78,19 +96,31 @@ rb_grn_index_cursor_each (VALUE self)
78
96
  {
79
97
  grn_obj *cursor;
80
98
  grn_ctx *context;
99
+ VALUE rb_table;
100
+ VALUE rb_lexicon;
81
101
 
82
102
  RETURN_ENUMERATOR(self, 0, NULL);
83
103
 
84
104
  rb_grn_index_cursor_deconstruct(SELF(self), &cursor, &context,
85
105
  NULL, NULL, NULL, NULL);
86
106
 
87
- if (context && cursor) {
88
- grn_posting *posting;
89
- grn_id tid;
107
+ if (!context) {
108
+ return Qnil;
109
+ }
110
+
111
+ if (!cursor) {
112
+ return Qnil;
113
+ }
90
114
 
91
- while ((posting = grn_index_cursor_next(context, cursor, &tid))) {
92
- rb_yield(rb_grn_posting_new(posting, tid));
115
+ rb_table = rb_iv_get(self, "@table");
116
+ rb_lexicon = rb_iv_get(self, "@lexicon");
117
+ while (GRN_TRUE) {
118
+ VALUE rb_posting;
119
+ rb_posting = next_value(context, cursor, rb_table, rb_lexicon);
120
+ if (NIL_P(rb_posting)) {
121
+ break;
93
122
  }
123
+ rb_yield(rb_posting);
94
124
  }
95
125
 
96
126
  return Qnil;
@@ -821,12 +821,26 @@ rb_grn_object_inspect_content_flags_with_label (VALUE inspected,
821
821
  case GRN_COLUMN_FIX_SIZE:
822
822
  case GRN_COLUMN_VAR_SIZE:
823
823
  case GRN_TYPE:
824
- if (flags & GRN_OBJ_KEY_UINT)
825
- rb_ary_push(inspected_flags, rb_str_new2("KEY_UINT"));
826
- if (flags & GRN_OBJ_KEY_INT)
827
- rb_ary_push(inspected_flags, rb_str_new2("KEY_INT"));
828
- if (flags & GRN_OBJ_KEY_FLOAT)
829
- rb_ary_push(inspected_flags, rb_str_new2("KEY_FLOAT"));
824
+ if (flags & GRN_OBJ_KEY_VAR_SIZE) {
825
+ rb_ary_push(inspected_flags, rb_str_new2("KEY_VAR_SIZE"));
826
+ } else {
827
+ switch (flags & GRN_OBJ_KEY_MASK) {
828
+ case GRN_OBJ_KEY_UINT:
829
+ rb_ary_push(inspected_flags, rb_str_new2("KEY_UINT"));
830
+ break;
831
+ case GRN_OBJ_KEY_INT:
832
+ rb_ary_push(inspected_flags, rb_str_new2("KEY_INT"));
833
+ break;
834
+ case GRN_OBJ_KEY_FLOAT:
835
+ rb_ary_push(inspected_flags, rb_str_new2("KEY_FLOAT"));
836
+ break;
837
+ case GRN_OBJ_KEY_GEO_POINT:
838
+ rb_ary_push(inspected_flags, rb_str_new2("KEY_GEO_POINT"));
839
+ break;
840
+ default:
841
+ break;
842
+ }
843
+ }
830
844
  break;
831
845
  default:
832
846
  break;
@@ -19,7 +19,7 @@
19
19
 
20
20
  #include "rb-grn.h"
21
21
 
22
- grn_rc grn_obj_cast(grn_ctx *ctx, grn_obj *src, grn_obj *dest, int addp);
22
+ grn_rc grn_obj_cast(grn_ctx *ctx, grn_obj *src, grn_obj *dest, grn_bool addp);
23
23
 
24
24
  #define SELF(object) ((RbGrnTableKeySupport *)DATA_PTR(object))
25
25
 
@@ -770,7 +770,7 @@ rb_grn_patricia_trie_open_grn_near_cursor (int argc, VALUE *argv, VALUE self,
770
770
  grn_ctx_at(*context, table->header.domain));
771
771
  GRN_OBJ_INIT(&casted_key, GRN_BULK, 0, table->header.domain);
772
772
  if (key_p->header.domain != table->header.domain) {
773
- grn_obj_cast(*context, key_p, &casted_key, 0);
773
+ grn_obj_cast(*context, key_p, &casted_key, GRN_FALSE);
774
774
  grn_obj_unlink(*context, key_p);
775
775
  key_p = &casted_key;
776
776
  }
@@ -1,6 +1,7 @@
1
1
  /* -*- coding: utf-8; c-file-style: "ruby" -*- */
2
2
  /*
3
3
  Copyright (C) 2011 Haruka Yoshihara <yoshihara@clear-code.com>
4
+ Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
4
5
 
5
6
  This library is free software; you can redistribute it and/or
6
7
  modify it under the terms of the GNU Lesser General Public
@@ -21,7 +22,8 @@
21
22
  VALUE rb_cGrnPosting;
22
23
 
23
24
  VALUE
24
- rb_grn_posting_new (grn_posting *posting, grn_id term_id)
25
+ rb_grn_posting_new (grn_posting *posting, grn_id term_id,
26
+ VALUE rb_table, VALUE rb_lexicon)
25
27
  {
26
28
  VALUE parameters;
27
29
 
@@ -40,6 +42,9 @@ rb_grn_posting_new (grn_posting *posting, grn_id term_id)
40
42
 
41
43
  #undef SET_PARAMETER
42
44
 
45
+ rb_hash_aset(parameters, ID2SYM(rb_intern("table")), rb_table);
46
+ rb_hash_aset(parameters, ID2SYM(rb_intern("lexicon")), rb_lexicon);
47
+
43
48
  return rb_funcall(rb_cGrnPosting, rb_intern("new"), 1,
44
49
  parameters);
45
50
  }
@@ -1,6 +1,6 @@
1
1
  /* -*- coding: utf-8; c-file-style: "ruby" -*- */
2
2
  /*
3
- Copyright (C) 2009 Kouhei Sutou <kou@clear-code.com>
3
+ Copyright (C) 2009-2012 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
@@ -129,12 +129,115 @@ rb_grn_type_initialize (int argc, VALUE *argv, VALUE self)
129
129
  return Qnil;
130
130
  }
131
131
 
132
+ static VALUE
133
+ rb_grn_type_size (VALUE self)
134
+ {
135
+ grn_ctx *context;
136
+ grn_obj *type;
137
+
138
+ type = RVAL2GRNOBJECT(self, &context);
139
+
140
+ return UINT2NUM(grn_obj_get_range(context, type));
141
+ }
142
+
143
+ static VALUE
144
+ rb_grn_type_flags (VALUE self)
145
+ {
146
+ grn_ctx *context;
147
+ grn_obj *type;
148
+
149
+ type = RVAL2GRNOBJECT(self, &context);
150
+
151
+ return UINT2NUM(type->header.flags);
152
+ }
153
+
154
+ static VALUE
155
+ rb_grn_type_fixed_size_p (VALUE self)
156
+ {
157
+ grn_ctx *context;
158
+ grn_obj *type;
159
+
160
+ type = RVAL2GRNOBJECT(self, &context);
161
+
162
+ return CBOOL2RVAL(!(type->header.flags & GRN_OBJ_KEY_VAR_SIZE));
163
+ }
164
+
165
+ static VALUE
166
+ rb_grn_type_variable_size_p (VALUE self)
167
+ {
168
+ grn_ctx *context;
169
+ grn_obj *type;
170
+
171
+ type = RVAL2GRNOBJECT(self, &context);
172
+
173
+ return CBOOL2RVAL(type->header.flags & GRN_OBJ_KEY_VAR_SIZE);
174
+ }
175
+
176
+ static VALUE
177
+ rb_grn_type_unsigned_integer_p (VALUE self)
178
+ {
179
+ grn_obj *type;
180
+ grn_obj_flags key_type;
181
+
182
+ type = RVAL2GRNOBJECT(self, NULL);
183
+ key_type = type->header.flags & GRN_OBJ_KEY_MASK;
184
+ return CBOOL2RVAL(key_type == GRN_OBJ_KEY_UINT);
185
+ }
186
+
187
+ static VALUE
188
+ rb_grn_type_integer_p (VALUE self)
189
+ {
190
+ grn_obj *type;
191
+ grn_obj_flags key_type;
192
+
193
+ type = RVAL2GRNOBJECT(self, NULL);
194
+ key_type = type->header.flags & GRN_OBJ_KEY_MASK;
195
+ return CBOOL2RVAL(key_type == GRN_OBJ_KEY_INT);
196
+ }
197
+
198
+ static VALUE
199
+ rb_grn_type_float_p (VALUE self)
200
+ {
201
+ grn_obj *type;
202
+ grn_obj_flags key_type;
203
+
204
+ type = RVAL2GRNOBJECT(self, NULL);
205
+ key_type = type->header.flags & GRN_OBJ_KEY_MASK;
206
+ return CBOOL2RVAL(key_type == GRN_OBJ_KEY_FLOAT);
207
+ }
208
+
209
+ static VALUE
210
+ rb_grn_type_geo_point_p (VALUE self)
211
+ {
212
+ grn_obj *type;
213
+ grn_obj_flags key_type;
214
+
215
+ type = RVAL2GRNOBJECT(self, NULL);
216
+ key_type = type->header.flags & GRN_OBJ_KEY_MASK;
217
+ return CBOOL2RVAL(key_type == GRN_OBJ_KEY_GEO_POINT);
218
+ }
219
+
132
220
  void
133
221
  rb_grn_init_type (VALUE mGrn)
134
222
  {
135
223
  rb_cGrnType = rb_define_class_under(mGrn, "Type", rb_cGrnObject);
136
224
 
137
225
  rb_define_method(rb_cGrnType, "initialize", rb_grn_type_initialize, -1);
226
+ rb_define_method(rb_cGrnType, "size", rb_grn_type_size, 0);
227
+ rb_define_method(rb_cGrnType, "flags", rb_grn_type_flags, 0);
228
+ rb_define_method(rb_cGrnType, "fixed_size?", rb_grn_type_fixed_size_p, 0);
229
+ rb_define_method(rb_cGrnType, "variable_size?",
230
+ rb_grn_type_variable_size_p, 0);
231
+
232
+ rb_define_method(rb_cGrnType, "unsigned_integer?",
233
+ rb_grn_type_unsigned_integer_p, 0);
234
+ rb_define_alias(rb_cGrnType, "uint?", "unsigned_integer?");
235
+
236
+ rb_define_method(rb_cGrnType, "integer?", rb_grn_type_integer_p, 0);
237
+ rb_define_alias(rb_cGrnType, "int?", "integer?");
238
+
239
+ rb_define_method(rb_cGrnType, "float?", rb_grn_type_float_p, 0);
240
+ rb_define_method(rb_cGrnType, "geo_point?", rb_grn_type_geo_point_p, 0);
138
241
 
139
242
  /* 任意のテーブルに属する全てのレコード(Object型はv1.2で
140
243
  サポートされます)。 */
data/ext/groonga/rb-grn.h CHANGED
@@ -76,7 +76,7 @@ RB_GRN_BEGIN_DECLS
76
76
 
77
77
  #define RB_GRN_MAJOR_VERSION 2
78
78
  #define RB_GRN_MINOR_VERSION 0
79
- #define RB_GRN_MICRO_VERSION 6
79
+ #define RB_GRN_MICRO_VERSION 7
80
80
 
81
81
  #define RB_GRN_QUERY_DEFAULT_MAX_EXPRESSIONS 32
82
82
 
@@ -503,7 +503,9 @@ void rb_grn_expression_finalizer (grn_ctx *context,
503
503
  RbGrnExpression *rb_grn_expression);
504
504
 
505
505
  VALUE rb_grn_posting_new (grn_posting *posting,
506
- grn_id term_id);
506
+ grn_id term_id,
507
+ VALUE rb_table,
508
+ VALUE rb_lexicon);
507
509
 
508
510
  VALUE rb_grn_tokyo_geo_point_new (int latitude,
509
511
  int longitude);
@@ -582,8 +584,9 @@ VALUE rb_grn_column_expression_builder_build
582
584
  #define GRNCOLUMN2RVAL(klass, context, column, owner) \
583
585
  (rb_grn_column_to_ruby_object(klass, context, column, owner))
584
586
 
585
- #define GRNINDEXCURSOR2RVAL(context, cursor) \
586
- (rb_grn_index_cursor_to_ruby_object(context, cursor, GRN_TRUE))
587
+ #define GRNINDEXCURSOR2RVAL(context, cursor, rb_table, rb_lexicon) \
588
+ (rb_grn_index_cursor_to_ruby_object(context, cursor, rb_table, rb_lexicon, \
589
+ GRN_TRUE))
587
590
 
588
591
  #define RVAL2GRNACCESSOR(object) \
589
592
  (rb_grn_accessor_from_ruby_object(object))
@@ -695,6 +698,8 @@ VALUE rb_grn_column_to_ruby_object (VALUE klass,
695
698
  grn_bool owner);
696
699
  VALUE rb_grn_index_cursor_to_ruby_object (grn_ctx *context,
697
700
  grn_obj *cursor,
701
+ VALUE rb_table,
702
+ VALUE rb_lexicon,
698
703
  grn_bool owner);
699
704
 
700
705
  grn_operator rb_grn_operator_from_ruby_object (VALUE object);
data/lib/groonga.rb CHANGED
@@ -96,5 +96,5 @@ require 'groonga/patricia-trie'
96
96
  require 'groonga/dumper'
97
97
  require 'groonga/schema'
98
98
  require 'groonga/pagination'
99
- require 'groonga/query-log'
99
+ # require 'groonga/query-log'
100
100
  require 'groonga/grntest-log'
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2011 Kouhei Sutou <kou@clear-code.com>
3
+ # Copyright (C) 2011-2012 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
@@ -43,6 +43,12 @@ module Groonga
43
43
  # The number of rest posting information for the term ID.
44
44
  attr_accessor :n_rest_postings
45
45
 
46
+ # @return [Groonga::Table] The table of the record ID.
47
+ attr_reader :table
48
+
49
+ # @return [Groonga::Table] The table of the term ID.
50
+ attr_reader :lexicon
51
+
46
52
  # Creates a new Posting.
47
53
  #
48
54
  # @return The new Posting.
@@ -61,6 +67,8 @@ module Groonga
61
67
  # @option parameters [Integer] :term_frequency The term_frequency.
62
68
  # @option parameters [Integer] :weight The weight.
63
69
  # @option parameters [Integer] :n_rest_postings The n_rest_postings.
70
+ # @option parameters [Groonga::Table] :table The table of the record ID.
71
+ # @option parameters [Groonga::Table] :lexicon The table of the term ID.
64
72
  def update(parameters)
65
73
  @record_id = parameters[:record_id] || nil
66
74
  @section_id = parameters[:section_id] || nil
@@ -69,6 +77,8 @@ module Groonga
69
77
  @term_frequency = parameters[:term_frequency] || 0
70
78
  @weight = parameters[:weight] || 0
71
79
  @n_rest_postings = parameters[:n_rest_postings] || 0
80
+ @table = parameters[:table]
81
+ @lexicon = parameters[:lexicon]
72
82
  end
73
83
 
74
84
  # Returns Hash created from attributes.
@@ -83,5 +93,23 @@ module Groonga
83
93
  :n_rest_postings => @n_rest_postings
84
94
  }
85
95
  end
96
+
97
+ # @return [Groonga::Record, nil] The record for the record ID.
98
+ # If table isn't assosiated, nil is returned.
99
+ #
100
+ # @since 2.0.6
101
+ def record
102
+ return nil unless @table
103
+ Record.new(@table, @record_id)
104
+ end
105
+
106
+ # @return [Groonga::Record, nil] The record for the term ID.
107
+ # If lexicon isn't assosiated, nil is returned.
108
+ #
109
+ # @since 2.0.6
110
+ def term
111
+ return nil unless @lexicon
112
+ Record.new(@lexicon, @term_id)
113
+ end
86
114
  end
87
115
  end
@@ -66,6 +66,30 @@ class IndexCursorTest < Test::Unit::TestCase
66
66
  assert_true(opened)
67
67
  end
68
68
 
69
+ def test_record
70
+ record = nil
71
+ @terms.open_cursor do |table_cursor|
72
+ @content_index.open_cursor(table_cursor) do |cursor|
73
+ posting = cursor.next
74
+ record = posting.record
75
+ end
76
+ end
77
+
78
+ assert_equal("1", record.key)
79
+ end
80
+
81
+ def test_term
82
+ term = nil
83
+ @terms.open_cursor do |table_cursor|
84
+ @content_index.open_cursor(table_cursor) do |cursor|
85
+ posting = cursor.next
86
+ term = posting.term
87
+ end
88
+ end
89
+
90
+ assert_equal("l", term.key)
91
+ end
92
+
69
93
  private
70
94
  def create_hashes(keys, values)
71
95
  hashes = []
@@ -81,7 +105,9 @@ class IndexCursorTest < Test::Unit::TestCase
81
105
 
82
106
  def setup_schema
83
107
  Groonga::Schema.define do |schema|
84
- schema.create_table("Articles") do |table|
108
+ schema.create_table("Articles",
109
+ :type => :hash,
110
+ :key_type => :short_text) do |table|
85
111
  table.text("content")
86
112
  end
87
113
 
@@ -98,9 +124,9 @@ class IndexCursorTest < Test::Unit::TestCase
98
124
  end
99
125
 
100
126
  def setup_records
101
- @articles.add(:content => "l")
102
- @articles.add(:content => "ll")
103
- @articles.add(:content => "hello")
127
+ @articles.add("1", :content => "l")
128
+ @articles.add("2", :content => "ll")
129
+ @articles.add("3", :content => "hello")
104
130
  end
105
131
 
106
132
  def expected_postings
data/test/test-schema.rb CHANGED
@@ -338,7 +338,7 @@ class SchemaTest < Test::Unit::TestCase
338
338
  "path: <#{path}>, " +
339
339
  "domain: <Posts>, " +
340
340
  "range: <Niku>, " +
341
- "flags: <COMPRESS_LZO>>",
341
+ "flags: <KEY_VAR_SIZE|COMPRESS_LZO>>",
342
342
  column.inspect)
343
343
  end
344
344
  end
data/test/test-type.rb CHANGED
@@ -33,6 +33,63 @@ class TypeTest < Test::Unit::TestCase
33
33
  exception.message)
34
34
  end
35
35
 
36
+ def test_size
37
+ assert_equal(4, Groonga["Int32"].size)
38
+ end
39
+
40
+ def test_flags
41
+ key_int = 0x01 << 3
42
+ assert_equal(key_int, Groonga["Int32"].flags)
43
+ end
44
+
45
+ def test_fixed_size?
46
+ assert_true(Groonga["Int32"].fixed_size?)
47
+ end
48
+
49
+ def test_not_fixed_size?
50
+ assert_false(Groonga["ShortText"].fixed_size?)
51
+ end
52
+
53
+ def test_variable_size?
54
+ assert_true(Groonga["ShortText"].variable_size?)
55
+ end
56
+
57
+ def test_not_variable_size?
58
+ assert_false(Groonga["Int32"].variable_size?)
59
+ end
60
+
61
+ def test_unsigned_integer?
62
+ assert_true(Groonga["UInt32"].unsigned_integer?)
63
+ end
64
+
65
+ def test_not_unsigned_integer?
66
+ assert_false(Groonga["Int32"].unsigned_integer?)
67
+ end
68
+
69
+ def test_integer?
70
+ assert_true(Groonga["Int32"].integer?)
71
+ end
72
+
73
+ def test_not_integer?
74
+ assert_false(Groonga["UInt32"].integer?)
75
+ end
76
+
77
+ def test_float?
78
+ assert_true(Groonga["Float"].float?)
79
+ end
80
+
81
+ def test_not_float?
82
+ assert_false(Groonga["UInt32"].float?)
83
+ end
84
+
85
+ def test_geo_point?
86
+ assert_true(Groonga["WGS84GeoPoint"].geo_point?)
87
+ end
88
+
89
+ def test_not_geo_point?
90
+ assert_false(Groonga["UInt32"].geo_point?)
91
+ end
92
+
36
93
  def test_builtins
37
94
  assert_equal_type("Object", Groonga::Type::OBJECT) # FIXME!!!
38
95
  assert_equal_type("Bool", Groonga::Type::BOOLEAN)
@@ -58,7 +115,7 @@ class TypeTest < Test::Unit::TestCase
58
115
  "path: (temporary), " +
59
116
  "domain: (nil), " +
60
117
  "range: <2147483648>, " +
61
- "flags: <>>",
118
+ "flags: <KEY_VAR_SIZE>>",
62
119
  context["<longtext>"].inspect)
63
120
  end
64
121
 
@@ -99,7 +99,7 @@ class VariableSizeColumnTest < Test::Unit::TestCase
99
99
  "path: <#{@users_name_column_path}>, " +
100
100
  "domain: <Users>, " +
101
101
  "range: <ShortText>, " +
102
- "flags: <>" +
102
+ "flags: <KEY_VAR_SIZE>" +
103
103
  ">",
104
104
  @name.inspect)
105
105
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rroonga
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.6
4
+ version: 2.0.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-25 00:00:00.000000000 Z
12
+ date: 2012-11-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: pkg-config
@@ -224,7 +224,6 @@ files:
224
224
  - lib/groonga/context.rb
225
225
  - lib/groonga/grntest-log.rb
226
226
  - lib/groonga/geo-point.rb
227
- - lib/groonga/query-log.rb
228
227
  - lib/groonga/pagination.rb
229
228
  - lib/groonga/command.rb
230
229
  - lib/groonga/schema.rb
@@ -312,7 +311,6 @@ files:
312
311
  - test/groonga-test-utils.rb
313
312
  - test/test-table-dumper.rb
314
313
  - test/test-schema-type.rb
315
- - test/test-query-log.rb
316
314
  - test/test-patricia-trie.rb
317
315
  - test/test-version.rb
318
316
  - test/test-table-traverse.rb
@@ -349,7 +347,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
349
347
  version: '0'
350
348
  segments:
351
349
  - 0
352
- hash: -4521341651743360062
350
+ hash: 3736378040968072494
353
351
  required_rubygems_version: !ruby/object:Gem::Requirement
354
352
  none: false
355
353
  requirements:
@@ -358,7 +356,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
358
356
  version: '0'
359
357
  segments:
360
358
  - 0
361
- hash: -4521341651743360062
359
+ hash: 3736378040968072494
362
360
  requirements: []
363
361
  rubyforge_project: groonga
364
362
  rubygems_version: 1.8.23
@@ -396,7 +394,6 @@ test_files:
396
394
  - test/groonga-test-utils.rb
397
395
  - test/test-table-dumper.rb
398
396
  - test/test-schema-type.rb
399
- - test/test-query-log.rb
400
397
  - test/test-patricia-trie.rb
401
398
  - test/test-version.rb
402
399
  - test/test-table-traverse.rb
@@ -1,348 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2011 Kouhei Sutou <kou@clear-code.com>
4
- #
5
- # This library is free software; you can redistribute it and/or
6
- # modify it under the terms of the GNU Lesser General Public
7
- # License version 2.1 as published by the Free Software Foundation.
8
- #
9
- # This library is distributed in the hope that it will be useful,
10
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
- # Lesser General Public License for more details.
13
- #
14
- # You should have received a copy of the GNU Lesser General Public
15
- # License along with this library; if not, write to the Free Software
16
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
-
18
- require "English"
19
- require "shellwords"
20
- require "cgi"
21
-
22
- module Groonga
23
- module QueryLog
24
- class Command
25
- class << self
26
- @@registered_commands = {}
27
- def register(name, klass)
28
- @@registered_commands[name] = klass
29
- end
30
-
31
- def parse(input)
32
- if input.start_with?("/d/")
33
- parse_uri_path(input)
34
- else
35
- parse_command_line(input)
36
- end
37
- end
38
-
39
- private
40
- def parse_uri_path(path)
41
- name, parameters_string = path.split(/\?/, 2)
42
- parameters = {}
43
- if parameters_string
44
- parameters_string.split(/&/).each do |parameter_string|
45
- key, value = parameter_string.split(/\=/, 2)
46
- parameters[key] = CGI.unescape(value)
47
- end
48
- end
49
- name = name.gsub(/\A\/d\//, '')
50
- name, output_type = name.split(/\./, 2)
51
- parameters["output_type"] = output_type if output_type
52
- command_class = @@registered_commands[name] || self
53
- command = command_class.new(name, parameters)
54
- command.original_format = :uri
55
- command
56
- end
57
-
58
- def parse_command_line(command_line)
59
- name, *options = Shellwords.shellwords(command_line)
60
- parameters = {}
61
- options.each_slice(2) do |key, value|
62
- parameters[key.gsub(/\A--/, '')] = value
63
- end
64
- command_class = @@registered_commands[name] || self
65
- command = command_class.new(name, parameters)
66
- command.original_format = :command
67
- command
68
- end
69
- end
70
-
71
- attr_reader :name, :parameters
72
- attr_accessor :original_format
73
- def initialize(name, parameters)
74
- @name = name
75
- @parameters = parameters
76
- @original_format = nil
77
- end
78
-
79
- def ==(other)
80
- other.is_a?(self.class) and
81
- @name == other.name and
82
- @parameters == other.parameters
83
- end
84
-
85
- def uri_format?
86
- @original_format == :uri
87
- end
88
-
89
- def command_format?
90
- @original_format == :command
91
- end
92
-
93
- def to_uri_format
94
- path = "/d/#{@name}"
95
- parameters = @parameters.dup
96
- output_type = parameters.delete("output_type")
97
- path << ".#{output_type}" if output_type
98
- unless parameters.empty?
99
- sorted_parameters = parameters.sort_by do |name, _|
100
- name.to_s
101
- end
102
- uri_parameters = sorted_parameters.collect do |name, value|
103
- "#{CGI.escape(name)}=#{CGI.escape(value)}"
104
- end
105
- path << "?"
106
- path << uri_parameters.join("&")
107
- end
108
- path
109
- end
110
-
111
- def to_command_format
112
- command_line = [@name]
113
- sorted_parameters = @parameters.sort_by do |name, _|
114
- name.to_s
115
- end
116
- sorted_parameters.each do |name, value|
117
- escaped_value = value.gsub(/[\n"\\]/) do
118
- special_character = $MATCH
119
- case special_character
120
- when "\n"
121
- "\\n"
122
- else
123
- "\\#{special_character}"
124
- end
125
- end
126
- command_line << "--#{name}"
127
- command_line << "\"#{escaped_value}\""
128
- end
129
- command_line.join(" ")
130
- end
131
- end
132
-
133
- class SelectCommand < Command
134
- register("select", self)
135
-
136
- def sortby
137
- @parameters["sortby"]
138
- end
139
-
140
- def scorer
141
- @parameters["scorer"]
142
- end
143
-
144
- def query
145
- @parameters["query"]
146
- end
147
-
148
- def filter
149
- @parameters["filter"]
150
- end
151
-
152
- def conditions
153
- @conditions ||= filter.split(/(?:&&|&!|\|\|)/).collect do |condition|
154
- condition = condition.strip
155
- condition = condition.gsub(/\A[\s\(]*/, '')
156
- condition = condition.gsub(/[\s\)]*\z/, '') unless /\(/ =~ condition
157
- condition
158
- end
159
- end
160
-
161
- def drilldowns
162
- @drilldowns ||= (@parameters["drilldown"] || "").split(/\s*,\s*/)
163
- end
164
-
165
- def output_columns
166
- @parameters["output_columns"]
167
- end
168
- end
169
-
170
- class Statistic
171
- attr_reader :context_id, :start_time, :raw_command
172
- attr_reader :elapsed, :return_code
173
- attr_accessor :slow_operation_threshold, :slow_response_threshold
174
- def initialize(context_id)
175
- @context_id = context_id
176
- @start_time = nil
177
- @command = nil
178
- @raw_command = nil
179
- @operations = []
180
- @elapsed = nil
181
- @return_code = 0
182
- @slow_operation_threshold = 0.1
183
- @slow_response_threshold = 0.2
184
- end
185
-
186
- def start(start_time, command)
187
- @start_time = start_time
188
- @raw_command = command
189
- end
190
-
191
- def finish(elapsed, return_code)
192
- @elapsed = elapsed
193
- @return_code = return_code
194
- end
195
-
196
- def command
197
- @command ||= Command.parse(@raw_command)
198
- end
199
-
200
- def elapsed_in_seconds
201
- nano_seconds_to_seconds(@elapsed)
202
- end
203
-
204
- def last_time
205
- @start_time + elapsed_in_seconds
206
- end
207
-
208
- def slow?
209
- elapsed_in_seconds >= @slow_response_threshold
210
- end
211
-
212
- def each_operation
213
- previous_elapsed = 0
214
- ensure_parse_command
215
- operation_context_context = {
216
- :filter_index => 0,
217
- :drilldown_index => 0,
218
- }
219
- @operations.each_with_index do |operation, i|
220
- relative_elapsed = operation[:elapsed] - previous_elapsed
221
- relative_elapsed_in_seconds = nano_seconds_to_seconds(relative_elapsed)
222
- previous_elapsed = operation[:elapsed]
223
- parsed_operation = {
224
- :i => i,
225
- :elapsed => operation[:elapsed],
226
- :elapsed_in_seconds => nano_seconds_to_seconds(operation[:elapsed]),
227
- :relative_elapsed => relative_elapsed,
228
- :relative_elapsed_in_seconds => relative_elapsed_in_seconds,
229
- :name => operation[:name],
230
- :context => operation_context(operation[:name],
231
- operation_context_context),
232
- :n_records => operation[:n_records],
233
- :slow? => slow_operation?(relative_elapsed_in_seconds),
234
- }
235
- yield parsed_operation
236
- end
237
- end
238
-
239
- def add_operation(operation)
240
- @operations << operation
241
- end
242
-
243
- def operations
244
- _operations = []
245
- each_operation do |operation|
246
- _operations << operation
247
- end
248
- _operations
249
- end
250
-
251
- def select_command?
252
- command.name == "select"
253
- end
254
-
255
- private
256
- def nano_seconds_to_seconds(nano_seconds)
257
- nano_seconds / 1000.0 / 1000.0 / 1000.0
258
- end
259
-
260
- def operation_context(label, context)
261
- case label
262
- when "filter"
263
- if @select_command.query and context[:query_used].nil?
264
- context[:query_used] = true
265
- "query: #{@select_command.query}"
266
- else
267
- index = context[:filter_index]
268
- context[:filter_index] += 1
269
- @select_command.conditions[index]
270
- end
271
- when "sort"
272
- @select_command.sortby
273
- when "score"
274
- @select_command.scorer
275
- when "output"
276
- @select_command.output_columns
277
- when "drilldown"
278
- index = context[:drilldown_index]
279
- context[:drilldown_index] += 1
280
- @select_command.drilldowns[index]
281
- else
282
- nil
283
- end
284
- end
285
-
286
- def ensure_parse_command
287
- return unless select_command?
288
- @select_command = SelectCommand.parse(@raw_command)
289
- end
290
-
291
- def slow_operation?(elapsed)
292
- elapsed >= @slow_operation_threshold
293
- end
294
- end
295
-
296
- class Parser
297
- def initialize
298
- end
299
-
300
- def parse(input, &block)
301
- current_statistics = {}
302
- input.each_line do |line|
303
- case line
304
- when /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)\.(\d+)\|(.+?)\|([>:<])/
305
- year, month, day, hour, minutes, seconds, micro_seconds =
306
- $1, $2, $3, $4, $5, $6, $7
307
- context_id = $8
308
- type = $9
309
- rest = $POSTMATCH.strip
310
- time_stamp = Time.local(year, month, day, hour, minutes, seconds,
311
- micro_seconds)
312
- parse_line(current_statistics,
313
- time_stamp, context_id, type, rest, &block)
314
- end
315
- end
316
- end
317
-
318
- private
319
- def parse_line(current_statistics,
320
- time_stamp, context_id, type, rest, &block)
321
- case type
322
- when ">"
323
- statistic = Statistic.new(context_id)
324
- statistic.start(time_stamp, rest)
325
- current_statistics[context_id] = statistic
326
- when ":"
327
- return unless /\A(\d+) (.+)\((\d+)\)/ =~ rest
328
- elapsed = $1
329
- name = $2
330
- n_records = $3.to_i
331
- statistic = current_statistics[context_id]
332
- return if statistic.nil?
333
- statistic.add_operation(:name => name,
334
- :elapsed => elapsed.to_i,
335
- :n_records => n_records)
336
- when "<"
337
- return unless /\A(\d+) rc=(\d+)/ =~ rest
338
- elapsed = $1
339
- return_code = $2
340
- statistic = current_statistics.delete(context_id)
341
- return if statistic.nil?
342
- statistic.finish(elapsed.to_i, return_code.to_i)
343
- block.call(statistic)
344
- end
345
- end
346
- end
347
- end
348
- end
@@ -1,258 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # Copyright (C) 2011 Kouhei Sutou <kou@clear-code.com>
3
- #
4
- # This library is free software; you can redistribute it and/or
5
- # modify it under the terms of the GNU Lesser General Public
6
- # License version 2.1 as published by the Free Software Foundation.
7
- #
8
- # This library is distributed in the hope that it will be useful,
9
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
- # Lesser General Public License for more details.
12
- #
13
- # You should have received a copy of the GNU Lesser General Public
14
- # License along with this library; if not, write to the Free Software
15
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
-
17
- require "cgi"
18
-
19
- module QueryLogTest
20
- module CommandParseTestUtils
21
- private
22
- def command(name, parameters)
23
- Groonga::QueryLog::Command.new(name, parameters)
24
- end
25
-
26
- def parse_http_path(command, parameters)
27
- path = "/d/#{command}.json"
28
- unless parameters.empty?
29
- uri_parameters = parameters.collect do |key, value|
30
- [CGI.escape(key.to_s), CGI.escape(value.to_s)].join("=")
31
- end
32
- path << "?"
33
- path << uri_parameters.join("&")
34
- end
35
- Groonga::QueryLog::Command.parse(path)
36
- end
37
-
38
- def parse_command_line(command, parameters)
39
- command_line = "#{command} --output_type json"
40
- parameters.each do |key, value|
41
- if /"| / =~ value
42
- escaped_value = '"' + value.gsub(/"/, '\"') + '"'
43
- else
44
- escaped_value = value
45
- end
46
- command_line << " --#{key} #{escaped_value}"
47
- end
48
- Groonga::QueryLog::Command.parse(command_line)
49
- end
50
- end
51
-
52
- module HTTPCommandParseTestUtils
53
- private
54
- def parse(command, parameters={})
55
- parse_http_path(command, parameters)
56
- end
57
- end
58
-
59
- module CommandLineCommandParseTestUtils
60
- private
61
- def parse(command, parameters={})
62
- parse_command_line(command, parameters)
63
- end
64
- end
65
-
66
- module SelectCommandParseTests
67
- include CommandParseTestUtils
68
-
69
- def test_parameters
70
- select = parse("select",
71
- :table => "Users",
72
- :filter => "age<=30")
73
- assert_equal(command("select",
74
- "table" => "Users",
75
- "filter" => "age<=30",
76
- "output_type" => "json"),
77
- select)
78
- end
79
-
80
- def test_scorer
81
- select = parse("select",
82
- :table => "Users",
83
- :filter => "age<=30",
84
- :scorer => "_score = random()")
85
- assert_equal("_score = random()", select.scorer)
86
- end
87
-
88
- def test_to_uri_format
89
- select = parse("select",
90
- :table => "Users",
91
- :filter => "age<=30")
92
- assert_equal("/d/select.json?filter=age%3C%3D30&table=Users",
93
- select.to_uri_format)
94
- end
95
-
96
- def test_to_command_format
97
- select = parse("select",
98
- :table => "Users",
99
- :filter => "age<=30")
100
- assert_equal("select --filter \"age<=30\" " +
101
- "--output_type \"json\" --table \"Users\"",
102
- select.to_command_format)
103
- end
104
- end
105
-
106
- module SelectCommandParseFilterTests
107
- include CommandParseTestUtils
108
-
109
- def test_parenthesis
110
- filter = 'geo_in_rectangle(location,' +
111
- '"35.73360x139.7394","62614x139.7714") && ' +
112
- '((type == "たいやき" || type == "和菓子")) && ' +
113
- 'keyword @ "たいやき" &! keyword @ "白" &! keyword @ "養殖"'
114
- select = parse("select",
115
- :table => "Users",
116
- :filter => filter)
117
- assert_equal(['geo_in_rectangle(location,' +
118
- '"35.73360x139.7394","62614x139.7714")',
119
- 'type == "たいやき"',
120
- 'type == "和菓子"',
121
- 'keyword @ "たいやき"',
122
- 'keyword @ "白"',
123
- 'keyword @ "養殖"'],
124
- select.conditions)
125
- end
126
-
127
- def test_to_uri_format
128
- filter = 'geo_in_rectangle(location,' +
129
- '"35.73360x139.7394","62614x139.7714") && ' +
130
- '((type == "たいやき" || type == "和菓子")) && ' +
131
- 'keyword @ "たいやき" &! keyword @ "白" &! keyword @ "養殖"'
132
- select = parse("select",
133
- :table => "Users",
134
- :filter => filter)
135
- assert_equal("/d/select.json?filter=geo_in_rectangle%28location%2C" +
136
- "%2235.73360x139.7394%22%2C%2262614x139.7714%22%29+" +
137
- "%26%26+%28%28type+" +
138
- "%3D%3D+%22%E3%81%9F%E3%81%84%E3%82%84%E3%81%8D%22+" +
139
- "%7C%7C+type+%3D%3D+" +
140
- "%22%E5%92%8C%E8%8F%93%E5%AD%90%22%29%29+" +
141
- "%26%26+keyword+%40+" +
142
- "%22%E3%81%9F%E3%81%84%E3%82%84%E3%81%8D%22+%26%21+" +
143
- "keyword+%40+%22%E7%99%BD%22+%26%21+" +
144
- "keyword+%40+%22%E9%A4%8A%E6%AE%96%22&table=Users",
145
- select.to_uri_format)
146
- end
147
-
148
- def test_to_command_format
149
- filter = 'geo_in_rectangle(location,' +
150
- '"35.73360x139.7394","62614x139.7714") && ' +
151
- '((type == "たいやき" || type == "和菓子")) && ' +
152
- 'keyword @ "たいやき" &! keyword @ "白" &! keyword @ "養殖"'
153
- select = parse("select",
154
- :table => "Users",
155
- :filter => filter)
156
- assert_equal("select " +
157
- "--filter " +
158
- "\"geo_in_rectangle(location," +
159
- "\\\"35.73360x139.7394\\\",\\\"62614x139.7714\\\") && " +
160
- "((type == \\\"たいやき\\\" || " +
161
- "type == \\\"和菓子\\\")) && " +
162
- "keyword @ \\\"たいやき\\\" &! keyword @ \\\"白\\\" &! " +
163
- "keyword @ \\\"養殖\\\"\" " +
164
- "--output_type \"json\" --table \"Users\"",
165
- select.to_command_format)
166
- end
167
- end
168
-
169
- class HTTPSelectCommandParseTest < Test::Unit::TestCase
170
- include SelectCommandParseTests
171
- include SelectCommandParseFilterTests
172
- include HTTPCommandParseTestUtils
173
-
174
- def test_uri_format?
175
- command = parse("status")
176
- assert_predicate(command, :uri_format?)
177
- end
178
-
179
- def test_command_format?
180
- command = parse("status")
181
- assert_not_predicate(command, :command_format?)
182
- end
183
- end
184
-
185
- class CommandLineSelecCommandParseTest < Test::Unit::TestCase
186
- include SelectCommandParseTests
187
- include SelectCommandParseFilterTests
188
- include CommandLineCommandParseTestUtils
189
-
190
- def test_uri_format?
191
- command = parse("status")
192
- assert_not_predicate(command, :uri_format?)
193
- end
194
-
195
- def test_command_format?
196
- command = parse("status")
197
- assert_predicate(command, :command_format?)
198
- end
199
- end
200
-
201
- class StatisticOperationParseTest < Test::Unit::TestCase
202
- def test_context
203
- operations = statistics.first.operations.collect do |operation|
204
- [operation[:name], operation[:context]]
205
- end
206
- expected = [
207
- ["filter", "local_name @ \"gsub\""],
208
- ["filter", "description @ \"string\""],
209
- ["select", nil],
210
- ["sort", "_score"],
211
- ["output", "_key"],
212
- ["drilldown", "name"],
213
- ["drilldown", "class"],
214
- ]
215
- assert_equal(expected, operations)
216
- end
217
-
218
- def test_n_records
219
- operations = statistics.first.operations.collect do |operation|
220
- [operation[:name], operation[:n_records]]
221
- end
222
- expected = [
223
- ["filter", 15],
224
- ["filter", 13],
225
- ["select", 13],
226
- ["sort", 10],
227
- ["output", 10],
228
- ["drilldown", 3],
229
- ["drilldown", 2],
230
- ]
231
- assert_equal(expected, operations)
232
- end
233
-
234
- private
235
- def log
236
- <<-EOL
237
- 2011-06-02 16:27:04.731685|5091e5c0|>/d/select.join?table=Entries&filter=local_name+%40+%22gsub%22+%26%26+description+%40+%22string%22&sortby=_score&output_columns=_key&drilldown=name,class
238
- 2011-06-02 16:27:04.733539|5091e5c0|:000000001849451 filter(15)
239
- 2011-06-02 16:27:04.734978|5091e5c0|:000000003293459 filter(13)
240
- 2011-06-02 16:27:04.735012|5091e5c0|:000000003327415 select(13)
241
- 2011-06-02 16:27:04.735096|5091e5c0|:000000003411824 sort(10)
242
- 2011-06-02 16:27:04.735232|5091e5c0|:000000003547265 output(10)
243
- 2011-06-02 16:27:04.735606|5091e5c0|:000000003921419 drilldown(3)
244
- 2011-06-02 16:27:04.735762|5091e5c0|:000000004077552 drilldown(2)
245
- 2011-06-02 16:27:04.735808|5091e5c0|<000000004123726 rc=0
246
- EOL
247
- end
248
-
249
- def statistics
250
- statistics = []
251
- parser = Groonga::QueryLog::Parser.new
252
- parser.parse(StringIO.new(log)) do |statistic|
253
- statistics << statistic
254
- end
255
- statistics
256
- end
257
- end
258
- end