rroonga 2.0.6 → 2.0.7

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