rroonga 7.0.2 → 7.1.1
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.
- checksums.yaml +4 -4
- data/Rakefile +2 -2
- data/doc/text/news.md +46 -7
- data/ext/groonga/rb-grn-array.c +1 -272
- data/ext/groonga/rb-grn-column-cache.c +240 -0
- data/ext/groonga/rb-grn-column.c +1 -1
- data/ext/groonga/rb-grn-context.c +28 -4
- data/ext/groonga/rb-grn-expression.c +23 -1
- data/ext/groonga/rb-grn-object.c +44 -1
- data/ext/groonga/rb-grn-procedure.c +16 -1
- data/ext/groonga/rb-grn-query-logger.c +55 -6
- data/ext/groonga/rb-grn-table.c +170 -1
- data/ext/groonga/rb-grn-utils.c +21 -2
- data/ext/groonga/rb-grn.h +18 -3
- data/ext/groonga/rb-groonga.c +2 -1
- data/lib/groonga.rb +8 -5
- data/lib/groonga/column.rb +0 -5
- data/lib/groonga/database.rb +0 -10
- data/lib/groonga/index-column.rb +0 -10
- data/lib/groonga/query-logger.rb +1 -1
- data/rroonga-build.rb +6 -6
- data/rroonga.gemspec +1 -1
- data/test/groonga-test-utils.rb +5 -8
- data/test/test-array.rb +1 -131
- data/test/test-column-cache.rb +46 -0
- data/test/test-command-select.rb +36 -1
- data/test/test-context.rb +1 -2
- data/test/test-database.rb +16 -2
- data/test/test-logger.rb +13 -1
- data/test/test-procedure.rb +7 -1
- data/test/test-query-logger.rb +12 -1
- data/test/test-table-arrow.rb +193 -0
- data/test/test-table-offset-and-limit.rb +3 -1
- metadata +65 -64
- data/lib/groonga/statistic-measurer.rb +0 -37
- data/lib/groonga/table.rb +0 -25
- data/test/test-statistic-measurer.rb +0 -55
data/ext/groonga/rb-grn-utils.c
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
/* -*-
|
1
|
+
/* -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2
2
|
/* vim: set sts=4 sw=4 ts=8 noet: */
|
3
3
|
/*
|
4
|
-
Copyright (C) 2009-
|
4
|
+
Copyright (C) 2009-2017 Kouhei Sutou <kou@clear-code.com>
|
5
5
|
|
6
6
|
This library is free software; you can redistribute it and/or
|
7
7
|
modify it under the terms of the GNU Lesser General Public
|
@@ -126,6 +126,25 @@ rb_grn_convert_to_array (VALUE object)
|
|
126
126
|
return rb_convert_type(object, RUBY_T_ARRAY, "Array", "to_ary");
|
127
127
|
}
|
128
128
|
|
129
|
+
VALUE
|
130
|
+
rb_grn_convert_to_path (VALUE object)
|
131
|
+
{
|
132
|
+
VALUE path;
|
133
|
+
|
134
|
+
path = rb_grn_check_convert_to_string(object);
|
135
|
+
if (NIL_P(path)) {
|
136
|
+
ID to_path;
|
137
|
+
CONST_ID(to_path, "to_path");
|
138
|
+
path = rb_check_funcall(object, to_path, 0, 0);
|
139
|
+
if (path == Qundef) {
|
140
|
+
path = object;
|
141
|
+
}
|
142
|
+
path = rb_grn_convert_to_string(path);
|
143
|
+
}
|
144
|
+
|
145
|
+
return path;
|
146
|
+
}
|
147
|
+
|
129
148
|
VALUE
|
130
149
|
rb_grn_check_convert_to_string (VALUE object)
|
131
150
|
{
|
data/ext/groonga/rb-grn.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/* -*- coding: utf-8; mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2
2
|
/*
|
3
|
-
Copyright (C) 2009-
|
3
|
+
Copyright (C) 2009-2018 Kouhei Sutou <kou@clear-code.com>
|
4
4
|
Copyright (C) 2015-2017 Masafumi Yokoyama <yokoyama@clear-code.com>
|
5
5
|
|
6
6
|
This library is free software; you can redistribute it and/or
|
@@ -98,8 +98,8 @@ RB_GRN_BEGIN_DECLS
|
|
98
98
|
#endif
|
99
99
|
|
100
100
|
#define RB_GRN_MAJOR_VERSION 7
|
101
|
-
#define RB_GRN_MINOR_VERSION
|
102
|
-
#define RB_GRN_MICRO_VERSION
|
101
|
+
#define RB_GRN_MINOR_VERSION 1
|
102
|
+
#define RB_GRN_MICRO_VERSION 1
|
103
103
|
|
104
104
|
#define RB_GRN_OBJECT(object) ((RbGrnObject *)(object))
|
105
105
|
#define RB_GRN_NAMED_OBJECT(object) ((RbGrnNamedObject *)(object))
|
@@ -248,6 +248,18 @@ struct _RbGrnPlugin
|
|
248
248
|
grn_id id;
|
249
249
|
};
|
250
250
|
|
251
|
+
typedef struct _RbGrnColumnCache RbGrnColumnCache;
|
252
|
+
struct _RbGrnColumnCache
|
253
|
+
{
|
254
|
+
VALUE self;
|
255
|
+
grn_ctx *context;
|
256
|
+
VALUE rb_column;
|
257
|
+
grn_column_cache *column_cache;
|
258
|
+
grn_obj buffer;
|
259
|
+
grn_obj *range;
|
260
|
+
grn_obj *table;
|
261
|
+
};
|
262
|
+
|
251
263
|
RB_GRN_VAR grn_bool rb_grn_exited;
|
252
264
|
|
253
265
|
RB_GRN_VAR VALUE rb_eGrnError;
|
@@ -306,6 +318,7 @@ RB_GRN_VAR VALUE rb_cGrnIndex;
|
|
306
318
|
RB_GRN_VAR VALUE rb_mGrnRequestCanceler;
|
307
319
|
RB_GRN_VAR VALUE rb_mGrnRequestTimer;
|
308
320
|
RB_GRN_VAR VALUE rb_cGrnRequestTimerID;
|
321
|
+
RB_GRN_VAR VALUE rb_cGrnColumnCache;
|
309
322
|
|
310
323
|
void rb_grn_init_utils (VALUE mGrn);
|
311
324
|
void rb_grn_init_exception (VALUE mGrn);
|
@@ -369,6 +382,7 @@ void rb_grn_init_request_timer_id (VALUE mGrn);
|
|
369
382
|
void rb_grn_init_id (VALUE mGrn);
|
370
383
|
void rb_grn_init_name (VALUE mGrn);
|
371
384
|
void rb_grn_init_default_cache (VALUE mGrn);
|
385
|
+
void rb_grn_init_column_cache (VALUE mGrn);
|
372
386
|
|
373
387
|
VALUE rb_grn_rc_to_exception (grn_rc rc);
|
374
388
|
void rb_grn_rc_check (grn_rc rc,
|
@@ -404,6 +418,7 @@ grn_bool rb_grn_equal_string (const char *string1,
|
|
404
418
|
const char *string2);
|
405
419
|
VALUE rb_grn_convert_to_string (VALUE object);
|
406
420
|
VALUE rb_grn_convert_to_array (VALUE object);
|
421
|
+
VALUE rb_grn_convert_to_path (VALUE object);
|
407
422
|
VALUE rb_grn_check_convert_to_string (VALUE object);
|
408
423
|
VALUE rb_grn_check_convert_to_array (VALUE object);
|
409
424
|
VALUE rb_grn_check_convert_to_hash (VALUE object);
|
data/ext/groonga/rb-groonga.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/* -*- coding: utf-8; mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2
2
|
/*
|
3
|
-
Copyright (C) 2009-
|
3
|
+
Copyright (C) 2009-2018 Kouhei Sutou <kou@clear-code.com>
|
4
4
|
Copyright (C) 2016 Masafumi Yokoyama <yokoyama@clear-code.com>
|
5
5
|
|
6
6
|
This library is free software; you can redistribute it and/or
|
@@ -257,4 +257,5 @@ Init_groonga (void)
|
|
257
257
|
rb_grn_init_id(mGrn);
|
258
258
|
rb_grn_init_name(mGrn);
|
259
259
|
rb_grn_init_default_cache(mGrn);
|
260
|
+
rb_grn_init_column_cache(mGrn);
|
260
261
|
}
|
data/lib/groonga.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
#
|
3
|
-
# Copyright (C) 2009-2013 Kouhei Sutou <kou@clear-code.com>
|
1
|
+
# Copyright (C) 2009-2018 Kouhei Sutou <kou@clear-code.com>
|
4
2
|
#
|
5
3
|
# This library is free software; you can redistribute it and/or
|
6
4
|
# modify it under the terms of the GNU Lesser General Public
|
@@ -32,6 +30,13 @@ if local_groonga_bin_dir.exist?
|
|
32
30
|
end
|
33
31
|
|
34
32
|
prepend_path.call("PATH", File::PATH_SEPARATOR)
|
33
|
+
|
34
|
+
begin
|
35
|
+
require "ruby_installer/runtime"
|
36
|
+
rescue LoadError
|
37
|
+
else
|
38
|
+
RubyInstaller::Runtime.add_dll_directory(local_groonga_bin_dir.to_s)
|
39
|
+
end
|
35
40
|
end
|
36
41
|
|
37
42
|
require "groonga/geo-point"
|
@@ -91,9 +96,7 @@ module Groonga
|
|
91
96
|
end
|
92
97
|
|
93
98
|
require "groonga/context"
|
94
|
-
require "groonga/statistic-measurer"
|
95
99
|
require "groonga/database"
|
96
|
-
require "groonga/table"
|
97
100
|
require "groonga/column"
|
98
101
|
require "groonga/patricia-trie"
|
99
102
|
require "groonga/index-column"
|
data/lib/groonga/column.rb
CHANGED
@@ -17,11 +17,6 @@
|
|
17
17
|
|
18
18
|
module Groonga
|
19
19
|
class Column
|
20
|
-
def disk_usage
|
21
|
-
measurer = StatisticMeasurer.new
|
22
|
-
measurer.measure_disk_usage(path)
|
23
|
-
end
|
24
|
-
|
25
20
|
# @param [Groonga::Operator] operator (Groonga::Operator::MATCH)
|
26
21
|
# @return [Array<Groonga::IndexColumn>] Indexes on `column` which can
|
27
22
|
# execute `operator`.
|
data/lib/groonga/database.rb
CHANGED
@@ -44,16 +44,6 @@ module Groonga
|
|
44
44
|
paths
|
45
45
|
end
|
46
46
|
|
47
|
-
def disk_usage
|
48
|
-
return 0 if path.nil?
|
49
|
-
|
50
|
-
usage = 0
|
51
|
-
measurer = StatisticMeasurer.new
|
52
|
-
usage += measurer.measure_disk_usage(path)
|
53
|
-
usage += measurer.measure_disk_usage("%s.%07X" % [path, 0])
|
54
|
-
usage
|
55
|
-
end
|
56
|
-
|
57
47
|
def dump_index(output_directory)
|
58
48
|
each do |object|
|
59
49
|
next unless object.is_a?(Groonga::IndexColumn)
|
data/lib/groonga/index-column.rb
CHANGED
@@ -24,16 +24,6 @@ module Groonga
|
|
24
24
|
dumper = IndexColumnDumper.new(self, output_directory)
|
25
25
|
dumper.dump
|
26
26
|
end
|
27
|
-
|
28
|
-
def disk_usage
|
29
|
-
return 0 if path.nil?
|
30
|
-
|
31
|
-
usage = super
|
32
|
-
chunk_path = "#{path}.c"
|
33
|
-
measurer = StatisticMeasurer.new
|
34
|
-
usage += measurer.measure_disk_usage(chunk_path)
|
35
|
-
usage
|
36
|
-
end
|
37
27
|
end
|
38
28
|
|
39
29
|
class IndexColumnDumper
|
data/lib/groonga/query-logger.rb
CHANGED
data/rroonga-build.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2009-
|
1
|
+
# Copyright (C) 2009-2018 Kouhei Sutou <kou@clear-code.com>
|
2
2
|
# Copyright (C) 2015-2017 Masafumi Yokoyama <yokoyama@clear-code.com>
|
3
3
|
#
|
4
4
|
# This library is free software; you can redistribute it and/or
|
@@ -17,16 +17,16 @@
|
|
17
17
|
module RroongaBuild
|
18
18
|
module RequiredGroongaVersion
|
19
19
|
MAJOR = 7
|
20
|
-
MINOR =
|
21
|
-
MICRO =
|
20
|
+
MINOR = 1
|
21
|
+
MICRO = 1
|
22
22
|
VERSION = [MAJOR, MINOR, MICRO]
|
23
|
-
RELEASED_DATE = Time.utc(
|
23
|
+
RELEASED_DATE = Time.utc(2018, 1, 29)
|
24
24
|
end
|
25
25
|
|
26
26
|
module LatestGroongaVersion
|
27
27
|
MAJOR = 7
|
28
|
-
MINOR =
|
29
|
-
MICRO =
|
28
|
+
MINOR = 1
|
29
|
+
MICRO = 1
|
30
30
|
VERSION = [MAJOR, MINOR, MICRO]
|
31
31
|
end
|
32
32
|
|
data/rroonga.gemspec
CHANGED
@@ -89,7 +89,7 @@ Gem::Specification.new do |s|
|
|
89
89
|
s.add_development_dependency("test-unit", [">= 3.0.0"])
|
90
90
|
s.add_development_dependency("rake")
|
91
91
|
s.add_development_dependency("rake-compiler", [">= 0.9.5"])
|
92
|
-
s.add_development_dependency("rake-compiler-dock", [">= 0.6.
|
92
|
+
s.add_development_dependency("rake-compiler-dock", [">= 0.6.2"])
|
93
93
|
s.add_development_dependency("bundler")
|
94
94
|
s.add_development_dependency("yard")
|
95
95
|
s.add_development_dependency("packnga", [">= 1.0.0"])
|
data/test/groonga-test-utils.rb
CHANGED
@@ -68,12 +68,10 @@ module GroongaTestUtils
|
|
68
68
|
@dump_log = false
|
69
69
|
|
70
70
|
@log_path = @tmp_dir + "groonga.log"
|
71
|
-
|
72
|
-
Groonga::Logger.register(logger)
|
71
|
+
Groonga::Logger.path = @log_path.to_s
|
73
72
|
|
74
73
|
@query_log_path = @tmp_dir + "groonga-query.log"
|
75
|
-
|
76
|
-
Groonga::QueryLogger.register(query_logger, :all => true)
|
74
|
+
Groonga::QueryLogger.path = @query_log_path.to_s
|
77
75
|
end
|
78
76
|
|
79
77
|
def setup_tables_directory
|
@@ -130,11 +128,10 @@ module GroongaTestUtils
|
|
130
128
|
|
131
129
|
def teardown_log_path
|
132
130
|
return unless @dump_log
|
133
|
-
log_path
|
134
|
-
|
135
|
-
header = "--- log: #{log_path} ---"
|
131
|
+
if @log_path.exist?(log_path)
|
132
|
+
header = "--- log: #{@log_path} ---"
|
136
133
|
puts(header)
|
137
|
-
puts(
|
134
|
+
puts(@log_path.read)
|
138
135
|
puts("-" * header.length)
|
139
136
|
end
|
140
137
|
if @query_log_path.exist?
|
data/test/test-array.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2009-
|
1
|
+
# Copyright (C) 2009-2018 Kouhei Sutou <kou@clear-code.com>
|
2
2
|
#
|
3
3
|
# This library is free software; you can redistribute it and/or
|
4
4
|
# modify it under the terms of the GNU Lesser General Public
|
@@ -157,134 +157,4 @@ class ArrayTest < Test::Unit::TestCase
|
|
157
157
|
user_ids = users.each.collect(&:id)
|
158
158
|
assert_equal([1, 2, 3], user_ids)
|
159
159
|
end
|
160
|
-
|
161
|
-
class TestPushPull < self
|
162
|
-
def setup
|
163
|
-
@queue = Groonga::Array.create(:name => "Queue")
|
164
|
-
@queue.define_column("content", "ShortText")
|
165
|
-
end
|
166
|
-
|
167
|
-
def teardown
|
168
|
-
@queue = nil
|
169
|
-
end
|
170
|
-
|
171
|
-
def test_block?
|
172
|
-
Tempfile.open("output") do |output|
|
173
|
-
Tempfile.open("blocked_pull.rb") do |pull_rb|
|
174
|
-
pull_rb.puts(pull_rb_source(":block? => true"))
|
175
|
-
pull_rb.close
|
176
|
-
|
177
|
-
pid = spawn({}, RbConfig.ruby, pull_rb.path, :out => output.path)
|
178
|
-
sleep(0.5)
|
179
|
-
@queue.push do |record|
|
180
|
-
record.content = "The first record"
|
181
|
-
end
|
182
|
-
Process.waitpid(pid)
|
183
|
-
assert_equal(<<-EXPECTED_OUTPUT, output.read)
|
184
|
-
start
|
185
|
-
1, The first record
|
186
|
-
done
|
187
|
-
EXPECTED_OUTPUT
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
def test_not_block?
|
193
|
-
Tempfile.open("output") do |output|
|
194
|
-
Tempfile.open("not_blocked_pull.rb") do |pull_rb|
|
195
|
-
pull_rb.puts(pull_rb_source(":block? => false"))
|
196
|
-
pull_rb.close
|
197
|
-
|
198
|
-
pid = spawn({}, RbConfig.ruby, pull_rb.path, :out => output.path)
|
199
|
-
Process.waitpid(pid)
|
200
|
-
assert_equal(<<-EXPECTED_OUTPUT, output.read)
|
201
|
-
start
|
202
|
-
done
|
203
|
-
EXPECTED_OUTPUT
|
204
|
-
|
205
|
-
@queue.push do |record|
|
206
|
-
record.content = "The first record"
|
207
|
-
end
|
208
|
-
pid = spawn({}, RbConfig.ruby, pull_rb.path, :out => output.path)
|
209
|
-
Process.waitpid(pid)
|
210
|
-
output.rewind
|
211
|
-
assert_equal(<<-EXPECTED_OUTPUT, output.read)
|
212
|
-
start
|
213
|
-
1, The first record
|
214
|
-
done
|
215
|
-
EXPECTED_OUTPUT
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
def test_unblock
|
221
|
-
IO.pipe do |read_io, write_io|
|
222
|
-
Tempfile.open("not_blocked_pull.rb") do |pull_rb|
|
223
|
-
pull_rb.puts(pull_rb_source(":block? => true"))
|
224
|
-
pull_rb.close
|
225
|
-
|
226
|
-
pid = spawn({}, RbConfig.ruby, pull_rb.path, :out => write_io)
|
227
|
-
assert_equal("start", read_io.gets.chomp)
|
228
|
-
Process.kill(:TERM, pid)
|
229
|
-
@queue.unblock
|
230
|
-
assert_equal("SIGTERM", read_io.gets.chomp)
|
231
|
-
wait_finished(pid)
|
232
|
-
write_io.close
|
233
|
-
assert_equal("done", read_io.read.chomp)
|
234
|
-
end
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
private
|
239
|
-
def pull_rb_source(options)
|
240
|
-
base_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
241
|
-
<<-CODE
|
242
|
-
$stdout.sync = true
|
243
|
-
|
244
|
-
base_dir = #{base_dir.dump}
|
245
|
-
|
246
|
-
groonga_command_dir = File.join(base_dir, "..", "groonga-command")
|
247
|
-
if File.exist?(groonga_command_dir)
|
248
|
-
$LOAD_PATH.unshift(File.join(groonga_command_dir, "lib"))
|
249
|
-
end
|
250
|
-
|
251
|
-
groonga_client_dir = File.join(base_dir, "..", "groonga-client")
|
252
|
-
if File.exist?(groonga_client_dir)
|
253
|
-
$LOAD_PATH.unshift(File.join(groonga_client_dir, "lib"))
|
254
|
-
end
|
255
|
-
|
256
|
-
ext_dir = File.join(base_dir, "ext", "groonga")
|
257
|
-
lib_dir = File.join(base_dir, "lib")
|
258
|
-
|
259
|
-
$LOAD_PATH.unshift(ext_dir)
|
260
|
-
$LOAD_PATH.unshift(lib_dir)
|
261
|
-
|
262
|
-
require "groonga"
|
263
|
-
|
264
|
-
trap(:TERM) do
|
265
|
-
puts("SIGTERM")
|
266
|
-
end
|
267
|
-
|
268
|
-
puts("start")
|
269
|
-
Groonga::Context.default.open_database(#{@database_path.to_s.dump}) do
|
270
|
-
queue = Groonga["Queue"]
|
271
|
-
queue.pull(#{options}) do |record|
|
272
|
-
puts([record.id, record.content].join(", "))
|
273
|
-
end
|
274
|
-
end
|
275
|
-
puts("done")
|
276
|
-
CODE
|
277
|
-
end
|
278
|
-
|
279
|
-
def wait_finished(pid)
|
280
|
-
n_retries = 3
|
281
|
-
n_retries.times do |i|
|
282
|
-
@queue.unblock
|
283
|
-
finished_pid = Process.waitpid(pid, Process::WNOHANG)
|
284
|
-
return if finished_pid
|
285
|
-
sleep((2 ** i) * 0.1)
|
286
|
-
end
|
287
|
-
Process.waitpid(pid)
|
288
|
-
end
|
289
|
-
end
|
290
160
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Copyright (C) 2018 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This library is free software; you can redistribute it and/or
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
5
|
+
# License version 2.1 as published by the Free Software Foundation.
|
6
|
+
#
|
7
|
+
# This library is distributed in the hope that it will be useful,
|
8
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
9
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
10
|
+
# Lesser General Public License for more details.
|
11
|
+
#
|
12
|
+
# You should have received a copy of the GNU Lesser General Public
|
13
|
+
# License along with this library; if not, write to the Free Software
|
14
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
15
|
+
|
16
|
+
class ColumnCacheTest < Test::Unit::TestCase
|
17
|
+
include GroongaTestUtils
|
18
|
+
|
19
|
+
def setup
|
20
|
+
setup_database
|
21
|
+
|
22
|
+
setup_users_table
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup_users_table
|
26
|
+
Groonga::Schema.define do |schema|
|
27
|
+
schema.create_table("Users", :type => :hash) do |table|
|
28
|
+
table.integer32("age")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
@users = context["Users"]
|
33
|
+
@users.add("alice", :age => 9)
|
34
|
+
@users.add("bob", :age => 19)
|
35
|
+
@users.add("chris", :age => 29)
|
36
|
+
|
37
|
+
@age = @users.column("age")
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_array_reference
|
41
|
+
Groonga::ColumnCache.open(@age) do |column_cache|
|
42
|
+
assert_equal(@users.collect(&:age),
|
43
|
+
@users.collect {|user| column_cache[user]})
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|