groonga-command 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. data/Gemfile +21 -0
  2. data/README.md +47 -0
  3. data/Rakefile +44 -0
  4. data/doc/text/lgpl-2.1.txt +502 -0
  5. data/doc/text/news.md +5 -0
  6. data/groonga-command.gemspec +64 -0
  7. data/lib/groonga/command.rb +20 -0
  8. data/lib/groonga/command/base.rb +138 -0
  9. data/lib/groonga/command/column-create.rb +39 -0
  10. data/lib/groonga/command/column-remove.rb +36 -0
  11. data/lib/groonga/command/column-rename.rb +37 -0
  12. data/lib/groonga/command/delete.rb +38 -0
  13. data/lib/groonga/command/error.rb +24 -0
  14. data/lib/groonga/command/get.rb +39 -0
  15. data/lib/groonga/command/load.rb +56 -0
  16. data/lib/groonga/command/parser.rb +424 -0
  17. data/lib/groonga/command/select.rb +69 -0
  18. data/lib/groonga/command/suggest.rb +47 -0
  19. data/lib/groonga/command/table-create.rb +39 -0
  20. data/lib/groonga/command/table-remove.rb +35 -0
  21. data/lib/groonga/command/table-rename.rb +36 -0
  22. data/lib/groonga/command/truncate.rb +35 -0
  23. data/lib/groonga/command/version.rb +23 -0
  24. data/test/command/test-base.rb +114 -0
  25. data/test/command/test-column-create.rb +47 -0
  26. data/test/command/test-column-remove.rb +41 -0
  27. data/test/command/test-column-rename.rb +43 -0
  28. data/test/command/test-delete.rb +45 -0
  29. data/test/command/test-get.rb +44 -0
  30. data/test/command/test-load.rb +49 -0
  31. data/test/command/test-select.rb +60 -0
  32. data/test/command/test-suggest.rb +68 -0
  33. data/test/command/test-table-create.rb +48 -0
  34. data/test/command/test-table-remove.rb +39 -0
  35. data/test/command/test-table-rename.rb +41 -0
  36. data/test/command/test-truncate.rb +39 -0
  37. data/test/groonga-command-test-utils.rb +102 -0
  38. data/test/run-test.rb +39 -0
  39. data/test/test-parser.rb +353 -0
  40. metadata +237 -0
@@ -0,0 +1,41 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2012 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 as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ class TableRenameCommandTest < Test::Unit::TestCase
20
+ class CommandLineTest < self
21
+ include GroongaCommandTestUtils::CommandLineCommandParser
22
+
23
+ def test_ordered_arguments
24
+ name = "Users"
25
+ new_name = "People"
26
+
27
+ command = parse(name, new_name)
28
+ assert_instance_of(Groonga::Command::TableRename, command)
29
+ assert_equal({
30
+ :name => name,
31
+ :new_name => new_name,
32
+ },
33
+ command.arguments)
34
+ end
35
+
36
+ private
37
+ def parse(*arguments)
38
+ super("table_rename", arguments, :output_type => false)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,39 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2012 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 as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ class TruncateCommandTest < Test::Unit::TestCase
20
+ class CommandLineTest < self
21
+ include GroongaCommandTestUtils::CommandLineCommandParser
22
+
23
+ def test_ordered_arguments
24
+ table = "Users"
25
+
26
+ command = parse(table)
27
+ assert_instance_of(Groonga::Command::Truncate, command)
28
+ assert_equal({
29
+ :table => table,
30
+ },
31
+ command.arguments)
32
+ end
33
+
34
+ private
35
+ def parse(*arguments)
36
+ super("truncate", arguments, :output_type => false)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,102 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2011-2012 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 as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ require "cgi"
20
+ require "stringio"
21
+
22
+ require "groonga/command"
23
+
24
+ module GroongaCommandTestUtils
25
+ module CommandParser
26
+ private
27
+ def command(name, arguments)
28
+ Groonga::Command.find(name).new(name, arguments)
29
+ end
30
+
31
+ def parse_http_path(command, arguments, options={})
32
+ path = "/d/#{command}"
33
+ case options[:output_type]
34
+ when false
35
+ when nil
36
+ path << ".json"
37
+ else
38
+ path << ".#{options[:output_type]}"
39
+ end
40
+
41
+ unless arguments.empty?
42
+ uri_arguments = arguments.collect do |key, value|
43
+ [CGI.escape(key.to_s), CGI.escape(value.to_s)].join("=")
44
+ end
45
+ path << "?"
46
+ path << uri_arguments.join("&")
47
+ end
48
+
49
+ Groonga::Command::Parser.parse(path)
50
+ end
51
+
52
+ def parse_command_line(command, arguments, options={})
53
+ command_line = "#{command}"
54
+ case options[:output_type]
55
+ when false
56
+ when nil
57
+ command_line << " --output_type json"
58
+ else
59
+ command_line << " --output_type #{options[:output_type]}"
60
+ end
61
+
62
+ if arguments.is_a?(Hash)
63
+ arguments.each do |key, value|
64
+ escaped_value = escape_command_line_value(value)
65
+ command_line << " --#{key} #{escaped_value}"
66
+ end
67
+ else
68
+ arguments.each do |argument|
69
+ command_line << " #{escape_command_line_value(argument)}"
70
+ end
71
+ end
72
+
73
+ Groonga::Command::Parser.parse(command_line)
74
+ end
75
+
76
+ def escape_command_line_value(value)
77
+ if /"| / =~ value
78
+ '"' + value.gsub(/"/, '\"') + '"'
79
+ else
80
+ value
81
+ end
82
+ end
83
+ end
84
+
85
+ module HTTPCommandParser
86
+ include CommandParser
87
+
88
+ private
89
+ def parse(command, arguments={}, options={})
90
+ parse_http_path(command, arguments, options)
91
+ end
92
+ end
93
+
94
+ module CommandLineCommandParser
95
+ include CommandParser
96
+
97
+ private
98
+ def parse(command, arguments={}, options={})
99
+ parse_command_line(command, arguments, options)
100
+ end
101
+ end
102
+ end
data/test/run-test.rb ADDED
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (C) 2012 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 as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ $VERBOSE = true
20
+
21
+ $KCODE = "u" if RUBY_VERSION < "1.9"
22
+
23
+ base_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
24
+ lib_dir = File.join(base_dir, "lib")
25
+ test_dir = File.join(base_dir, "test")
26
+
27
+ require "test-unit"
28
+ require "test/unit/notify"
29
+
30
+ Test::Unit::Priority.enable
31
+
32
+ $LOAD_PATH.unshift(lib_dir)
33
+ $LOAD_PATH.unshift(test_dir)
34
+
35
+ require "groonga-command-test-utils"
36
+
37
+ ENV["TEST_UNIT_MAX_DIFF_TARGET_STRING_SIZE"] ||= "5000"
38
+
39
+ exit Test::Unit::AutoRunner.run(true, test_dir)
@@ -0,0 +1,353 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2011-2012 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 as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ class ParserTest < Test::Unit::TestCase
20
+ module ParseTests
21
+ def test_parameters
22
+ select = parse("select",
23
+ :table => "Users",
24
+ :filter => "age<=30")
25
+ assert_equal(command("select",
26
+ "table" => "Users",
27
+ "filter" => "age<=30",
28
+ "output_type" => "json"),
29
+ select)
30
+ end
31
+ end
32
+
33
+ class HTTPTest < self
34
+ include GroongaCommandTestUtils::HTTPCommandParser
35
+
36
+ def test_uri_format?
37
+ command = parse("status")
38
+ assert_predicate(command, :uri_format?)
39
+ end
40
+
41
+ def test_command_format?
42
+ command = parse("status")
43
+ assert_not_predicate(command, :command_format?)
44
+ end
45
+
46
+ class ParseTest < self
47
+ include ParseTests
48
+ end
49
+ end
50
+
51
+ class CommandLineTest < self
52
+ include GroongaCommandTestUtils::CommandLineCommandParser
53
+
54
+ def test_uri_format?
55
+ command = parse("status")
56
+ assert_not_predicate(command, :uri_format?)
57
+ end
58
+
59
+ def test_command_format?
60
+ command = parse("status")
61
+ assert_predicate(command, :command_format?)
62
+ end
63
+
64
+ class ParseTest < self
65
+ include ParseTests
66
+ end
67
+
68
+ class EventTest < self
69
+ def setup
70
+ @parser = Groonga::Command::Parser.new
71
+ end
72
+
73
+ class CommandTest < self
74
+ def test_newline
75
+ parsed_command = nil
76
+ @parser.on_command do |command|
77
+ parsed_command = command
78
+ end
79
+
80
+ @parser << "status"
81
+ assert_nil(parsed_command)
82
+ @parser << "\n"
83
+ assert_equal("status", parsed_command.name)
84
+ end
85
+
86
+ def test_finish
87
+ parsed_command = nil
88
+ @parser.on_command do |command|
89
+ parsed_command = command
90
+ end
91
+
92
+ @parser << "status"
93
+ assert_nil(parsed_command)
94
+ @parser.finish
95
+ assert_equal("status", parsed_command.name)
96
+ end
97
+
98
+ def test_empty_line
99
+ parsed_command = nil
100
+ @parser.on_command do |command|
101
+ parsed_command = command
102
+ end
103
+
104
+ @parser << "\n"
105
+ assert_nil(parsed_command)
106
+
107
+ @parser << "status\n"
108
+ assert_equal("status", parsed_command.name)
109
+ end
110
+ end
111
+
112
+ class LoadTest < self
113
+ def setup
114
+ super
115
+ @events = []
116
+ @parser.on_load_start do |command|
117
+ @events << [:load_start, command.original_source.dup]
118
+ end
119
+ @parser.on_load_columns do |command, header|
120
+ @events << [:load_columns, command.original_source.dup, header]
121
+ end
122
+ @parser.on_load_value do |command, value|
123
+ @events << [:load_value, command.original_source.dup, value]
124
+ end
125
+ @parser.on_load_complete do |command|
126
+ @events << [:load_complete, command.original_source.dup]
127
+ end
128
+ end
129
+
130
+ class InlineTest < self
131
+ class BracketTest < self
132
+ def test_have_columns
133
+ command_line =
134
+ "load " +
135
+ "--columns '_key, name' " +
136
+ "--values '[[\"alice\", \"Alice\"]]' " +
137
+ "--table Users"
138
+ @parser << command_line
139
+ assert_equal([], @events)
140
+ @parser << "\n"
141
+ assert_equal([
142
+ [:load_start, command_line],
143
+ [:load_columns, command_line, ["_key", "name"]],
144
+ [:load_value, command_line, ["alice", "Alice"]],
145
+ [:load_complete, command_line],
146
+ ],
147
+ @events)
148
+ end
149
+
150
+ def test_no_columns
151
+ command_line = "load --values '[[\"_key\"], [1]]' --table IDs"
152
+ @parser << command_line
153
+ assert_equal([], @events)
154
+ @parser << "\n"
155
+ assert_equal([
156
+ [:load_start, command_line],
157
+ [:load_columns, command_line, ["_key"]],
158
+ [:load_value, command_line, [1]],
159
+ [:load_complete, command_line],
160
+ ],
161
+ @events)
162
+ end
163
+ end
164
+
165
+ def test_brace
166
+ command_line = "load --values '[{\"_key\": 1}]' --table IDs"
167
+ @parser << command_line
168
+ assert_equal([], @events)
169
+ @parser << "\n"
170
+ assert_equal([
171
+ [:load_start, command_line],
172
+ [:load_value, command_line, {"_key" => 1}],
173
+ [:load_complete, command_line],
174
+ ],
175
+ @events)
176
+ end
177
+ end
178
+
179
+ class MultiLineTest < self
180
+ class BracketTest < self
181
+ def test_have_columns
182
+ @parser << <<-EOC
183
+ load --table Users --columns "_key, name"
184
+ [
185
+ ["alice", "Alice"]
186
+ ]
187
+ EOC
188
+ expected_events = []
189
+ expected_events << [:load_start, <<-EOC.chomp]
190
+ load --table Users --columns "_key, name"
191
+ EOC
192
+ expected_events << [:load_columns, <<-EOC.chomp, ["_key", "name"]]
193
+ load --table Users --columns "_key, name"
194
+ EOC
195
+ expected_events << [:load_value, <<-EOC.chomp, ["alice", "Alice"]]
196
+ load --table Users --columns "_key, name"
197
+ [
198
+ ["alice", "Alice"]
199
+ EOC
200
+ expected_events << [:load_complete, <<-EOC.chomp]
201
+ load --table Users --columns "_key, name"
202
+ [
203
+ ["alice", "Alice"]
204
+ ]
205
+ EOC
206
+ assert_equal(expected_events, @events)
207
+ end
208
+
209
+ def test_no_columns
210
+ @parser << <<-EOC
211
+ load --table Users
212
+ [
213
+ ["_key", "name"],
214
+ ["alice", "Alice"]
215
+ ]
216
+ EOC
217
+ expected_events = []
218
+ expected_events << [:load_start, <<-EOC.chomp]
219
+ load --table Users
220
+ EOC
221
+ expected_events << [:load_columns, <<-EOC.chomp, ["_key", "name"]]
222
+ load --table Users
223
+ [
224
+ ["_key", "name"]
225
+ EOC
226
+ expected_events << [:load_value, <<-EOC.chomp, ["alice", "Alice"]]
227
+ load --table Users
228
+ [
229
+ ["_key", "name"],
230
+ ["alice", "Alice"]
231
+ EOC
232
+ expected_events << [:load_complete, <<-EOC.chomp]
233
+ load --table Users
234
+ [
235
+ ["_key", "name"],
236
+ ["alice", "Alice"]
237
+ ]
238
+ EOC
239
+ assert_equal(expected_events, @events)
240
+ end
241
+ end
242
+
243
+ def test_brace
244
+ @parser << <<-EOC
245
+ load --table Users
246
+ [
247
+ {"_key": "alice", "name": "Alice"},
248
+ {"_key": "bob", "name": "Bob"}
249
+ ]
250
+ EOC
251
+ expected_events = []
252
+ expected_events << [:load_start, <<-EOC.chomp]
253
+ load --table Users
254
+ EOC
255
+ value = {"_key" => "alice", "name" => "Alice"}
256
+ expected_events << [:load_value, <<-EOC.chomp, value]
257
+ load --table Users
258
+ [
259
+ {"_key": "alice", "name": "Alice"}
260
+ EOC
261
+ value = {"_key" => "bob", "name" => "Bob"}
262
+ expected_events << [:load_value, <<-EOC.chomp, value]
263
+ load --table Users
264
+ [
265
+ {"_key": "alice", "name": "Alice"},
266
+ {"_key": "bob", "name": "Bob"}
267
+ EOC
268
+ expected_events << [:load_complete, <<-EOC.chomp]
269
+ load --table Users
270
+ [
271
+ {"_key": "alice", "name": "Alice"},
272
+ {"_key": "bob", "name": "Bob"}
273
+ ]
274
+ EOC
275
+ assert_equal(expected_events, @events)
276
+ end
277
+ end
278
+
279
+ class ErrorTest < self
280
+ def test_location
281
+ message = "record separate comma is missing"
282
+ before = "{\"_key\": \"alice\", \"name\": \"Alice\"}"
283
+ after = "\n{\"_key\": \"bob\""
284
+ error = Groonga::Command::ParseError.new(message, before, after)
285
+ assert_equal(<<-EOS.chomp, error.message)
286
+ record separate comma is missing:
287
+ {"_key": "alice", "name": "Alice"}
288
+ ^
289
+ {"_key": "bob"
290
+ EOS
291
+ end
292
+
293
+ def test_no_record_separate_comma
294
+ message = "record separate comma is missing"
295
+ before = "{\"_key\": \"alice\", \"name\": \"Alice\"}"
296
+ after = "\n{\"_key\": \"bob\""
297
+ error = Groonga::Command::ParseError.new(message, before, after)
298
+ assert_raise(error) do
299
+ @parser << <<-EOC
300
+ load --table Users
301
+ [
302
+ {"_key": "alice", "name": "Alice"}
303
+ {"_key": "bob", "name": "Bob"}
304
+ EOC
305
+ end
306
+ end
307
+
308
+ def test_garbage_before_json
309
+ message = "there are garbages before JSON"
310
+ before = "load --table Users\n"
311
+ after = "XXX\n"
312
+ error = Groonga::Command::ParseError.new(message, before, after)
313
+ assert_raise(error) do
314
+ @parser << <<-EOC
315
+ load --table Users
316
+ XXX
317
+ [
318
+ {"_key": "alice", "name": "Alice"}
319
+ ]
320
+ EOC
321
+ end
322
+ end
323
+ end
324
+ end
325
+
326
+ class CommentTest < self
327
+ def test_newline
328
+ parsed_comment = nil
329
+ @parser.on_comment do |comment|
330
+ parsed_comment = comment
331
+ end
332
+
333
+ @parser << "# status"
334
+ assert_nil(parsed_comment)
335
+ @parser << "\n"
336
+ assert_equal(" status", parsed_comment)
337
+ end
338
+
339
+ def test_finish
340
+ parsed_comment = nil
341
+ @parser.on_comment do |comment|
342
+ parsed_comment = comment
343
+ end
344
+
345
+ @parser << "# status"
346
+ assert_nil(parsed_comment)
347
+ @parser.finish
348
+ assert_equal(" status", parsed_comment)
349
+ end
350
+ end
351
+ end
352
+ end
353
+ end