rsql 0.2.4 → 0.2.5
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/LICENSE +1 -1
- data/README.rdoc +1 -1
- data/bin/rsql +88 -39
- data/extra/mysql-client-5.1.59-1.tgz +0 -0
- data/lib/rsql.rb +1 -1
- data/lib/rsql/commands.rb +17 -6
- data/lib/rsql/eval_context.rb +63 -8
- data/lib/rsql/mysql_results.rb +10 -3
- data/test/test_eval_context.rb +4 -3
- metadata +9 -9
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -100,7 +100,7 @@ downloaded with the source.
|
|
100
100
|
|
101
101
|
RSQL is licensed under the MIT License:
|
102
102
|
|
103
|
-
Copyright (C) 2011 by Brad Robel-Forrest <brad+rsql@gigglewax.com>
|
103
|
+
Copyright (C) 2011-2012 by Brad Robel-Forrest <brad+rsql@gigglewax.com>
|
104
104
|
|
105
105
|
Permission is hereby granted, free of charge, to any person obtaining
|
106
106
|
a copy of this software and associated documentation files (the
|
data/bin/rsql
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
# Copyright (C) 2011 by Brad Robel-Forrest <brad+rsql@gigglewax.com>
|
3
|
+
# Copyright (C) 2011-2012 by Brad Robel-Forrest <brad+rsql@gigglewax.com>
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -52,6 +52,9 @@ bn = File.basename($0, '.rb')
|
|
52
52
|
|
53
53
|
eval_context = EvalContext.new
|
54
54
|
|
55
|
+
# rewrite all double hyphen options into singles so both are supported
|
56
|
+
ARGV.map!{|a| a.sub(/^--/,'-')}
|
57
|
+
|
55
58
|
if i = ARGV.index('-rc')
|
56
59
|
ARGV.delete_at(i)
|
57
60
|
rc_fn = ARGV.delete_at(i)
|
@@ -146,13 +149,25 @@ end
|
|
146
149
|
|
147
150
|
if i = ARGV.index('-ssh')
|
148
151
|
require 'net/ssh'
|
152
|
+
|
149
153
|
ARGV.delete_at(i)
|
154
|
+
|
150
155
|
(ssh_host, ssh_user, ssh_password, ssh_port) = split_login(ARGV.delete_at(i))
|
156
|
+
|
157
|
+
default_config = File.join(ENV['HOME'], '.ssh', 'config')
|
158
|
+
if File.exists?(default_config)
|
159
|
+
ssh_cfghash = Net::SSH::Config.load(default_config, ssh_host)
|
160
|
+
end
|
161
|
+
|
162
|
+
if ssh_user.nil? || ssh_user.empty?
|
163
|
+
ssh_user = ssh_cfghash['user'] || ENV['USER'] || ENV['USERNAME']
|
164
|
+
end
|
151
165
|
end
|
152
166
|
|
153
167
|
if i = ARGV.index('-sshconfig')
|
154
168
|
ARGV.delete_at(i)
|
155
169
|
ssh_config = ARGV.delete_at(i)
|
170
|
+
ssh_cfghash = Net::SSH::Config.load(ssh_config, ssh_host)
|
156
171
|
end
|
157
172
|
|
158
173
|
if i = ARGV.index('-e')
|
@@ -167,7 +182,15 @@ if i = ARGV.index('-e')
|
|
167
182
|
batch_input.strip!
|
168
183
|
end
|
169
184
|
|
170
|
-
|
185
|
+
show_usage = false
|
186
|
+
ARGV.each do |a|
|
187
|
+
if a.start_with?('-')
|
188
|
+
$stderr.puts "unknown argument: #{a}"
|
189
|
+
show_usage = true
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
if ARGV.size < 1 || show_usage
|
171
194
|
prefix = ' ' << ' ' * bn.size
|
172
195
|
$stderr.puts <<USAGE
|
173
196
|
|
@@ -203,7 +226,8 @@ end
|
|
203
226
|
|
204
227
|
MySQLResults.database_name = ARGV.shift
|
205
228
|
|
206
|
-
|
229
|
+
if !$stdin.tty? && batch_input.nil?
|
230
|
+
# accept commands from stdin
|
207
231
|
batch_input = $stdin.read.gsub(/\r?\n/,';')
|
208
232
|
end
|
209
233
|
|
@@ -262,8 +286,9 @@ if ssh_host
|
|
262
286
|
ssh_pid = Process.fork do
|
263
287
|
File.open(ipc_fn,'w'){|f| f.puts('start')}
|
264
288
|
ssh_enabled = false
|
265
|
-
Signal.trap('INT')
|
266
|
-
|
289
|
+
Signal.trap('INT', 'IGNORE')
|
290
|
+
Signal.trap('TERM') do
|
291
|
+
$stderr.puts 'Closing SSH connection...' unless batch_input
|
267
292
|
ssh_enabled = false
|
268
293
|
end
|
269
294
|
opts = {:timeout => 15}
|
@@ -271,9 +296,7 @@ if ssh_host
|
|
271
296
|
if verbose
|
272
297
|
opts[:verbose] = :debug
|
273
298
|
puts "SSH options: #{opts.inspect}"
|
274
|
-
|
275
|
-
puts "SSH config: #{Net::SSH::Config.load(ssh_config, ssh_host).inspect}"
|
276
|
-
end
|
299
|
+
puts "SSH config: #{ssh_cfghash.inspect}"
|
277
300
|
end
|
278
301
|
begin
|
279
302
|
opts[:password] = ssh_password if ssh_password
|
@@ -292,20 +315,44 @@ if ssh_host
|
|
292
315
|
retry
|
293
316
|
end
|
294
317
|
end
|
318
|
+
rescue Timeout::Error => ex
|
319
|
+
$stderr.puts ex.message
|
320
|
+
ensure
|
321
|
+
if ssh_enabled
|
322
|
+
ssh.forward.local(mysql_port, mysql_host, remote_mysql_port)
|
323
|
+
unless batch_input
|
324
|
+
puts(verbose ? "ready (#{mysql_port} => #{remote_mysql_port})" : 'ready')
|
325
|
+
end
|
326
|
+
File.open(ipc_fn,'w'){|f| f.puts('ready')}
|
327
|
+
ssh.loop(1) { ssh_enabled }
|
328
|
+
end
|
329
|
+
File.open(ipc_fn,'w'){|f| f.puts('fail')}
|
295
330
|
end
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
331
|
+
end
|
332
|
+
|
333
|
+
at_exit do
|
334
|
+
if ssh_pid && 0 <= ssh_pid
|
335
|
+
begin
|
336
|
+
Process.kill('TERM', ssh_pid)
|
337
|
+
killed = false
|
338
|
+
5.times do
|
339
|
+
if Process.waitpid(ssh_pid, Process::WNOHANG)
|
340
|
+
killed = true
|
341
|
+
break
|
342
|
+
end
|
343
|
+
sleep 1
|
344
|
+
end
|
345
|
+
Process.kill('KILL', ssh_pid) unless killed
|
346
|
+
rescue Exception => ex
|
347
|
+
$stderr.puts ex.message
|
348
|
+
$stderr.puts ex.backtrace if verbose
|
300
349
|
end
|
301
|
-
File.open(ipc_fn,'w'){|f| f.puts('ready')}
|
302
|
-
ssh.loop(1) { ssh_enabled }
|
303
350
|
end
|
304
|
-
File.
|
351
|
+
File.unlink(ipc_fn) if File.exists?(ipc_fn)
|
305
352
|
end
|
306
353
|
|
307
354
|
ipc_state = ''
|
308
|
-
|
355
|
+
15.times do
|
309
356
|
sleep(1)
|
310
357
|
File.open(ipc_fn,'r'){|f| ipc_state = f.gets.strip}
|
311
358
|
break if ipc_state == 'ready' || ipc_state == 'fail'
|
@@ -314,6 +361,8 @@ if ssh_host
|
|
314
361
|
File.unlink(ipc_fn)
|
315
362
|
|
316
363
|
unless ipc_state == 'ready'
|
364
|
+
# give the child time to exit
|
365
|
+
sleep(0.5)
|
317
366
|
$stderr.puts "failed to connect to #{ssh_host} SSH host"
|
318
367
|
exit 1
|
319
368
|
end
|
@@ -332,6 +381,7 @@ mysql_conn = "#{mysql_host}:#{remote_mysql_port || mysql_port}"
|
|
332
381
|
begin
|
333
382
|
MySQLResults.conn = Mysql.new(mysql_host, mysql_user, mysql_password,
|
334
383
|
MySQLResults.database_name, mysql_port)
|
384
|
+
MySQLResults.conn.reconnect = true
|
335
385
|
puts 'connected' unless batch_input
|
336
386
|
rescue Mysql::Error => ex
|
337
387
|
if ex.message.include?('Client does not support authentication')
|
@@ -377,7 +427,7 @@ cmd_thread = Thread.new do
|
|
377
427
|
else
|
378
428
|
puts '',"[#{mysql_user}@#{ssh_host||mysql_host}:#{MySQLResults.database_name}]"
|
379
429
|
input = ''
|
380
|
-
prompt = bn + '> '
|
430
|
+
prompt = eval_context.prompt || (bn + '> ')
|
381
431
|
loop do
|
382
432
|
str = Readline.readline(prompt)
|
383
433
|
if str.nil?
|
@@ -410,28 +460,37 @@ cmd_thread = Thread.new do
|
|
410
460
|
next
|
411
461
|
end
|
412
462
|
|
413
|
-
me[:running] = true
|
414
463
|
break if cmds.run!(eval_context) == :done
|
415
|
-
me[:running] = false
|
416
464
|
end
|
417
465
|
end
|
418
466
|
|
467
|
+
# keep a secondary connection to allow us to kill off a running query
|
468
|
+
kill_conn = Mysql.new(mysql_host, mysql_user, mysql_password,
|
469
|
+
MySQLResults.database_name, mysql_port)
|
470
|
+
|
419
471
|
Signal.trap('INT') do
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
472
|
+
# emulate MySQL's behavior
|
473
|
+
if MySQLResults.conn && MySQLResults.conn.busy?
|
474
|
+
tid = MySQLResults.conn.thread_id
|
475
|
+
$stderr.puts "Ctrl-C -- sending \"KILL QUERY #{tid}\" to server..."
|
476
|
+
kill_conn.kill(tid)
|
477
|
+
10.times do
|
478
|
+
break unless MySQLResults.conn.busy?
|
479
|
+
sleep(0.5)
|
480
|
+
end
|
481
|
+
MySQLResults.conn.select_db(MySQLResults.database_name)
|
482
|
+
else
|
483
|
+
$stderr.puts 'Ctrl-C -- exit!'
|
484
|
+
cmd_thread[:shutdown] = true
|
485
|
+
sleep(0.3)
|
486
|
+
cmd_thread.kill
|
424
487
|
end
|
425
|
-
$stderr.puts 'Shutting down...'
|
426
|
-
cmd_thread[:shutdown] = true
|
427
|
-
sleep(0.3)
|
428
|
-
cmd_thread.kill
|
429
488
|
end
|
430
489
|
|
431
490
|
Signal.trap('CHLD') do
|
432
491
|
$stderr.puts "SSH child (#{ssh_pid}) stopped--shutting down..."
|
433
|
-
if
|
434
|
-
$stderr.puts '
|
492
|
+
if MySQLResults.conn && MySQLResults.conn.busy?
|
493
|
+
$stderr.puts 'Closing MySQL connection...'
|
435
494
|
safe_timeout(MySQLResults.conn, :close, 'MySQL')
|
436
495
|
MySQLResults.conn = nil
|
437
496
|
end
|
@@ -461,13 +520,3 @@ if Readline::HISTORY.any?
|
|
461
520
|
end
|
462
521
|
File.open(history_fn, 'w') {|f| YAML.dump(Readline::HISTORY.to_a, f)}
|
463
522
|
end
|
464
|
-
|
465
|
-
if ssh_pid && 0 <= ssh_pid
|
466
|
-
begin
|
467
|
-
Process.kill('INT', ssh_pid)
|
468
|
-
Process.waitpid(ssh_pid)
|
469
|
-
rescue Exception => ex
|
470
|
-
$stderr.puts ex.message
|
471
|
-
$stderr.puts ex.backtrace if verbose
|
472
|
-
end
|
473
|
-
end
|
Binary file
|
data/lib/rsql.rb
CHANGED
data/lib/rsql/commands.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (C) 2011 by Brad Robel-Forrest <brad+rsql@gigglewax.com>
|
2
|
+
# Copyright (C) 2011-2012 by Brad Robel-Forrest <brad+rsql@gigglewax.com>
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -82,7 +82,11 @@ module RSQL
|
|
82
82
|
match_before_bang = nil
|
83
83
|
break
|
84
84
|
end
|
85
|
-
|
85
|
+
if val.strip == 'nil'
|
86
|
+
new_bangs[key.strip] = nil
|
87
|
+
else
|
88
|
+
new_bangs[key.strip] = val.to_sym
|
89
|
+
end
|
86
90
|
end
|
87
91
|
next unless match_before_bang
|
88
92
|
match = match_before_bang
|
@@ -145,10 +149,16 @@ module RSQL
|
|
145
149
|
results.send(cmd.displayer)
|
146
150
|
elsif EvalResults === results
|
147
151
|
last_results = nil
|
148
|
-
if
|
149
|
-
|
152
|
+
if MySQLResults === results.value
|
153
|
+
# This happens if their recipe returns MySQL
|
154
|
+
# results...just display it like above.
|
155
|
+
results.value.send(cmd.displayer)
|
156
|
+
else
|
157
|
+
if results.stdout && 0 < results.stdout.size
|
158
|
+
puts results.stdout.string
|
159
|
+
end
|
160
|
+
puts "=> #{results.value.inspect}" if results.value
|
150
161
|
end
|
151
|
-
puts "=> #{results.value.inspect}" if results.value
|
152
162
|
end
|
153
163
|
end
|
154
164
|
end
|
@@ -213,7 +223,8 @@ module RSQL
|
|
213
223
|
begin
|
214
224
|
last_results = MySQLResults.query(value, eval_context)
|
215
225
|
rescue MySQLResults::MaxRowsException => ex
|
216
|
-
$stderr.puts "refusing to process #{ex.rows} rows (max: #{ex.max})"
|
226
|
+
$stderr.puts "refusing to process #{ex.rows} rows (max: #{ex.max})--" <<
|
227
|
+
"consider raising this via set_max_rows"
|
217
228
|
rescue Mysql::Error => ex
|
218
229
|
$stderr.puts ex.message
|
219
230
|
rescue Exception => ex
|
data/lib/rsql/eval_context.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (C) 2011 by Brad Robel-Forrest <brad+rsql@gigglewax.com>
|
2
|
+
# Copyright (C) 2011-2012 by Brad Robel-Forrest <brad+rsql@gigglewax.com>
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -24,8 +24,8 @@ module RSQL
|
|
24
24
|
require 'time'
|
25
25
|
|
26
26
|
################################################################################
|
27
|
-
# This class wraps all dynamic evaluation and serves as the reflection
|
28
|
-
#
|
27
|
+
# This class wraps all dynamic evaluation and serves as the reflection class
|
28
|
+
# for adding methods dynamically.
|
29
29
|
#
|
30
30
|
class EvalContext
|
31
31
|
|
@@ -35,19 +35,26 @@ module RSQL
|
|
35
35
|
HEXSTR_LIMIT = 32
|
36
36
|
|
37
37
|
def initialize(verbose=false)
|
38
|
+
@prompt = nil
|
38
39
|
@verbose = verbose
|
39
40
|
@hexstr_limit = HEXSTR_LIMIT
|
40
41
|
@results = nil
|
41
42
|
|
42
43
|
@loaded_fns = []
|
44
|
+
@loaded_fns_state = {}
|
43
45
|
@init_registrations = []
|
44
46
|
@bangs = {}
|
47
|
+
@global_bangs = {}
|
45
48
|
|
46
49
|
@registrations = {
|
47
50
|
:version => Registration.new('version', [], {},
|
48
51
|
method(:version),
|
49
52
|
'version',
|
50
53
|
'Version information about RSQL, the client, and the server.'),
|
54
|
+
:help => Registration.new('help', [], {},
|
55
|
+
method(:help),
|
56
|
+
'help',
|
57
|
+
'Show short syntax help.'),
|
51
58
|
:reload => Registration.new('reload', [], {},
|
52
59
|
method(:reload),
|
53
60
|
'reload',
|
@@ -71,6 +78,7 @@ module RSQL
|
|
71
78
|
}
|
72
79
|
end
|
73
80
|
|
81
|
+
attr_reader :prompt
|
74
82
|
attr_accessor :bangs, :verbose
|
75
83
|
|
76
84
|
def call_init_registrations
|
@@ -82,6 +90,9 @@ module RSQL
|
|
82
90
|
end
|
83
91
|
|
84
92
|
def load(fn, opt=nil)
|
93
|
+
@loaded_fns << fn unless @loaded_fns_state.key?(fn)
|
94
|
+
@loaded_fns_state[fn] = :loading
|
95
|
+
|
85
96
|
# this should only be done after we have established a
|
86
97
|
# mysql connection, so this option allows rsql to load the
|
87
98
|
# init file immediately and then later make the init
|
@@ -102,6 +113,7 @@ module RSQL
|
|
102
113
|
}.value
|
103
114
|
|
104
115
|
if Exception === ret
|
116
|
+
@loaded_fns_state[fn] = :failed
|
105
117
|
if @verbose
|
106
118
|
$stderr.puts("#{ex.class}: #{ex.message}", ex.backtrace)
|
107
119
|
else
|
@@ -110,7 +122,7 @@ module RSQL
|
|
110
122
|
end
|
111
123
|
ret = false
|
112
124
|
else
|
113
|
-
@
|
125
|
+
@loaded_fns_state[fn] = :loaded
|
114
126
|
call_init_registrations unless @skipping_init_registrations
|
115
127
|
ret = true
|
116
128
|
end
|
@@ -121,12 +133,35 @@ module RSQL
|
|
121
133
|
end
|
122
134
|
|
123
135
|
def reload
|
124
|
-
|
125
|
-
|
136
|
+
# some files may be loaded by other files, if so, we don't want to
|
137
|
+
# reload them again here
|
138
|
+
@loaded_fns.each{|fn| @loaded_fns_state[fn] = nil}
|
139
|
+
@loaded_fns.each{|fn| self.load(fn, :skip_init_registrations) if @loaded_fns_state[fn] == nil}
|
140
|
+
|
141
|
+
# load up the inits after all the normal registrations are ready
|
142
|
+
call_init_registrations
|
143
|
+
|
144
|
+
# report all the successfully loaded ones
|
145
|
+
loaded = []
|
146
|
+
@loaded_fns.each{|fn,state| loaded << fn if @loaded_fns_state[fn] == :loaded}
|
147
|
+
puts "loaded: #{loaded.inspect}"
|
126
148
|
end
|
127
149
|
|
128
150
|
def bang_eval(field, val)
|
129
|
-
|
151
|
+
# allow individual bangs to override global ones, even if they're nil
|
152
|
+
if @bangs.key?(field)
|
153
|
+
bang = @bangs[field]
|
154
|
+
else
|
155
|
+
@global_bangs.each do |m,b|
|
156
|
+
if (String === m && m == field.to_s) ||
|
157
|
+
(Regexp === m && m.match(field.to_s))
|
158
|
+
bang = b
|
159
|
+
break
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
if bang
|
130
165
|
begin
|
131
166
|
val = Thread.new{ eval("#{bang}(val)") }.value
|
132
167
|
rescue Exception => ex
|
@@ -421,6 +456,18 @@ module RSQL
|
|
421
456
|
"server:v#{MySQLResults.conn.server_info}"
|
422
457
|
end
|
423
458
|
|
459
|
+
# Show a short amount of information about acceptable syntax.
|
460
|
+
#
|
461
|
+
def help # :doc:
|
462
|
+
puts <<EOF
|
463
|
+
|
464
|
+
Converting values on the fly:
|
465
|
+
|
466
|
+
rsql> select name, value from rsql_example ! value => humanize_bytes;
|
467
|
+
|
468
|
+
EOF
|
469
|
+
end
|
470
|
+
|
424
471
|
# Provide a helper utility in the event a registered
|
425
472
|
# method would like to make its own queries.
|
426
473
|
#
|
@@ -438,13 +485,21 @@ module RSQL
|
|
438
485
|
nil
|
439
486
|
end
|
440
487
|
|
488
|
+
# Register bangs to evaluate on all displayers as long as a column
|
489
|
+
# match is located. Bang keys may be either exact string matches or
|
490
|
+
# regular expressions.
|
491
|
+
#
|
492
|
+
def register_global_bangs(bangs)
|
493
|
+
@global_bangs.merge!(bangs)
|
494
|
+
end
|
495
|
+
|
441
496
|
# Exactly like register below except in addition to registering as
|
442
497
|
# a usable call for later, we will also use these as soon as we
|
443
498
|
# have a connection to MySQL.
|
444
499
|
#
|
445
500
|
def register_init(sym, *args, &block) # :doc:
|
446
501
|
register(sym, *args, &block)
|
447
|
-
@init_registrations << sym
|
502
|
+
@init_registrations << sym unless @init_registrations.include?(sym)
|
448
503
|
end
|
449
504
|
|
450
505
|
# If given a block, allow the block to be called later, otherwise,
|
data/lib/rsql/mysql_results.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (C) 2011 by Brad Robel-Forrest <brad+rsql@gigglewax.com>
|
2
|
+
# Copyright (C) 2011-2012 by Brad Robel-Forrest <brad+rsql@gigglewax.com>
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -19,9 +19,16 @@
|
|
19
19
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
20
|
# THE SOFTWARE.
|
21
21
|
|
22
|
-
|
22
|
+
# The standard MySQL hooks block Ruby threads, this interface provides an
|
23
|
+
# asynchronous query.
|
24
|
+
#
|
25
|
+
require 'mysqlplus'
|
23
26
|
|
24
|
-
|
27
|
+
class Mysql
|
28
|
+
alias :query :async_query
|
29
|
+
end
|
30
|
+
|
31
|
+
module RSQL
|
25
32
|
|
26
33
|
########################################
|
27
34
|
# A wrapper to make it easier to work with MySQL results (and prettier).
|
data/test/test_eval_context.rb
CHANGED
@@ -30,8 +30,8 @@ class TestEvalContext < Test::Unit::TestCase
|
|
30
30
|
def test_reload
|
31
31
|
orig = $stdout
|
32
32
|
$stdout = out = StringIO.new
|
33
|
-
@conn.expects(:query).with(instance_of(String)).returns(nil)
|
34
|
-
@conn.expects(:affected_rows).returns(0)
|
33
|
+
@conn.expects(:query).with(instance_of(String)).returns(nil)
|
34
|
+
@conn.expects(:affected_rows).returns(0)
|
35
35
|
@ctx.safe_eval('reload', nil, out)
|
36
36
|
assert_match(/loaded: .+?example.rsqlrc/, out.string)
|
37
37
|
ensure
|
@@ -117,7 +117,8 @@ class TestEvalContext < Test::Unit::TestCase
|
|
117
117
|
end
|
118
118
|
|
119
119
|
def test_complete
|
120
|
-
|
120
|
+
out = @ctx.complete('')
|
121
|
+
assert_equal(19, out.size, out.inspect)
|
121
122
|
assert_equal(['version'], @ctx.complete('v'))
|
122
123
|
assert_equal(['.version'], @ctx.complete('.v'))
|
123
124
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rsql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 29
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 5
|
10
|
+
version: 0.2.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Brad Robel-Forrest
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2012-01-14 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: net-ssh
|
@@ -34,19 +34,19 @@ dependencies:
|
|
34
34
|
type: :runtime
|
35
35
|
version_requirements: *id001
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
|
-
name:
|
37
|
+
name: mysqlplus
|
38
38
|
prerelease: false
|
39
39
|
requirement: &id002 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ">="
|
43
43
|
- !ruby/object:Gem::Version
|
44
|
-
hash:
|
44
|
+
hash: 31
|
45
45
|
segments:
|
46
|
-
- 2
|
47
|
-
- 8
|
48
46
|
- 0
|
49
|
-
|
47
|
+
- 1
|
48
|
+
- 2
|
49
|
+
version: 0.1.2
|
50
50
|
type: :runtime
|
51
51
|
version_requirements: *id002
|
52
52
|
- !ruby/object:Gem::Dependency
|