rsql 0.2.8 → 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -4,19 +4,20 @@ Homepage:: https://rubygems.org/gems/rsql
4
4
 
5
5
  == DESCRIPTION
6
6
 
7
- This is an application to make working with a SQL command line more
8
- convenient by allowing interaction with recipes and Ruby code in
9
- addition to embedding the common operation of using a SSH connection
10
- to an intermediary host for access to the SQL server.
7
+ This is an application to make working with a SQL command line more convenient
8
+ by allowing interaction with recipes and Ruby code in addition to embedding the
9
+ common operation of using a SSH connection to an intermediary host for access to
10
+ the SQL server.
11
11
 
12
12
  === Installation
13
13
 
14
14
  gem install rsql
15
15
 
16
- Alternatively, RSQL can be downloaded as a tar.gz or zip and run
17
- directly from within the unpacked source directory as long as the
18
- MySQL Ruby library is available. SSH functionality will be disabled
19
- unless the Net::SSH Ruby library is also installed and available.
16
+ Alternatively, RSQL can be downloaded as a tar.gz or zip and run directly from
17
+ within the unpacked source directory as long as the {MySQL Ruby
18
+ library}[https://rubygems.org/gems/mysqlplus] is available. SSH functionality
19
+ will be disabled unless the {Net::SSH Ruby
20
+ library}[https://rubygems.org/gems/net-ssh] is also installed and available.
20
21
 
21
22
  == USAGE
22
23
 
@@ -33,68 +34,67 @@ RSQL is invoked from the command line using:
33
34
  Display details on SSH connections and evaluation stack traces.
34
35
 
35
36
  -rc _rcfile_::
36
- Override loading the .rsqlrc file from the HOME directory for one in
37
- a different location.
37
+ Override loading the .rsqlrc file from the HOME directory for one in a
38
+ different location.
38
39
 
39
40
  -maxrows _max_::
40
41
  Override the maximum number of rows to process.
41
42
 
42
43
  -batch _field_separator_::
43
- Run in batch mode using the separator specified (e.g. a /t will
44
- separate fields with a tab character).
44
+ Run in batch mode using the separator specified (e.g. a /t will separate
45
+ fields with a tab character).
45
46
 
46
47
  -ssh _ssh_host_::
47
48
  Establish a SSH connection before connecting to the MySQL host.
48
49
 
49
50
  -sshconfig _ssh_config_::
50
- Use a specific SSH configuration file instead of the default files
51
- loaded at runtime by Net::SSH.
51
+ Use a specific SSH configuration file instead of the default files loaded at
52
+ runtime by Net::SSH.
52
53
 
53
54
  -e [_query_]::
54
- Run a query from the command line (i.e. not interactive). If a
55
- _query_ is not provided, STDIN will be read. Multiple commands can
56
- be issued in one set by separation with semicolons just as if they
57
- had been provided at the RSQL prompt interactively. This option
58
- *must* be the last option specified.
55
+ Run a query from the command line (i.e. not interactive). If a _query_ is not
56
+ provided, STDIN will be read. Multiple commands can be issued in one set by
57
+ separation with semicolons just as if they had been provided at the RSQL
58
+ prompt interactively. This option *must* be the last option specified.
59
59
 
60
- The _ssh_host_ and _mysql_host_ arguments may optionally include
61
- _user_, _password_, or _port_ values using the following syntax:
60
+ The _ssh_host_ and _mysql_host_ arguments may optionally include _user_,
61
+ _password_, or _port_ values using the following syntax:
62
62
 
63
63
  [<user>[:<password>]@]<host>[:<port>]
64
64
 
65
- Once at the +rsql+ prompt, normal MySQL queries can be entered as
66
- expected, ending each with a semicolon (;) for columnar output or \\G
67
- for line-by-line output formatting.
65
+ Once at the +rsql+ prompt, normal MySQL queries can be entered as expected,
66
+ ending each with a semicolon (;) for columnar output or \\G for line-by-line
67
+ output formatting.
68
68
 
69
- Ruby commands will be evaluated for any content entered at the RSQL
70
- prompt beginning with a period.
69
+ Ruby commands will be evaluated for any content entered at the RSQL prompt
70
+ beginning with a period.
71
71
 
72
72
  ==== Command Line Examples
73
73
 
74
- Connect as the "root" user to a MySQL server running on the local
75
- host, with no password (because there are no characters listed between
76
- the colon and the at sign):
74
+ Connect as the "root" user to a MySQL server running on the local host, with no
75
+ password (because there are no characters listed between the colon and the at
76
+ sign):
77
77
 
78
78
  rsql root:@127.0.0.1
79
79
 
80
- Connect as the "readonly" user to the "internal.database.acme.com"
81
- host's MySQL server after establishing a SSH tunnel to the
82
- "external.acme.com" gateway. In this case, we are expecting that our
83
- SSH configuration is set up with the right user name. Because we did
84
- not provide a password for MySQL, one will be obtained directly from
85
- the console (without echoing the characters typed):
80
+ Connect as the "readonly" user to the "internal.database.acme.com" host's MySQL
81
+ server after establishing a SSH tunnel to the "external.acme.com" gateway. In
82
+ this case, we are expecting that our SSH configuration is set up with the right
83
+ user name. Because we did not provide a password for MySQL, one will be obtained
84
+ directly from the console (without echoing the characters typed):
86
85
 
87
86
  rsql -ssh external.acme.com readonly@internal.database.acme.com
88
87
 
89
88
  == GETTING STARTED
90
89
 
91
- This example walks through many features of RSQL including how to
92
- build up recipes:
90
+ This example walks through many features of RSQL including how to build up
91
+ recipes:
93
92
 
94
- https://github.com/bradrf/rsql/raw/master/example.rsqlrc
93
+ Try out the simple examples in rdoc-ref:example.rsqlrc.rdoc for a painless
94
+ introduciton for how to leverage RSQL.
95
95
 
96
- The file is available as example.rsqlrc installed with the gem or
97
- downloaded with the source.
96
+ The file is available as example.rsqlrc installed with the gem or downloaded
97
+ with the source.
98
98
 
99
99
  == LICENSE
100
100
 
@@ -102,21 +102,19 @@ RSQL is licensed under the MIT License:
102
102
 
103
103
  Copyright (C) 2011-2012 by Brad Robel-Forrest <brad+rsql@gigglewax.com>
104
104
 
105
- Permission is hereby granted, free of charge, to any person obtaining
106
- a copy of this software and associated documentation files (the
107
- "Software"), to deal in the Software without restriction, including
108
- without limitation the rights to use, copy, modify, merge, publish,
109
- distribute, sublicense, and/or sell copies of the Software, and to
110
- permit persons to whom the Software is furnished to do so, subject to
111
- the following conditions:
112
-
113
- The above copyright notice and this permission notice shall be
114
- included in all copies or substantial portions of the Software.
115
-
116
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
117
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
118
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
119
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
120
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
121
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
122
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
105
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
106
+ this software and associated documentation files (the "Software"), to deal in
107
+ the Software without restriction, including without limitation the rights to
108
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
109
+ the Software, and to permit persons to whom the Software is furnished to do so,
110
+ subject to the following conditions:
111
+
112
+ The above copyright notice and this permission notice shall be included in all
113
+ copies or substantial portions of the Software.
114
+
115
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
116
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
117
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
118
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
119
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
120
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/bin/rsql CHANGED
@@ -179,14 +179,14 @@ end
179
179
 
180
180
  if i = ARGV.index('-e')
181
181
  ARGV.delete_at(i)
182
- batch_input = ''
182
+ opts.batch_input = ''
183
183
  ARGV.delete_if do |arg|
184
184
  arg_i = ARGV.index(arg)
185
185
  if i <= arg_i
186
- batch_input << ' ' << arg
186
+ opts.batch_input << ' ' << arg
187
187
  end
188
188
  end
189
- batch_input.strip!
189
+ opts.batch_input.strip!
190
190
  end
191
191
 
192
192
  show_usage = false
@@ -235,9 +235,9 @@ end
235
235
 
236
236
  MySQLResults.database_name = ARGV.shift
237
237
 
238
- if !$stdin.tty? && batch_input.nil?
238
+ if !$stdin.tty? && opts.batch_input.nil?
239
239
  # accept commands from stdin
240
- batch_input = $stdin.read.gsub(/\r?\n/,';')
240
+ opts.batch_input = $stdin.read.gsub(/\r?\n/,';')
241
241
  end
242
242
 
243
243
  # make sure we remove any duplicates when we add to the history to
@@ -277,7 +277,7 @@ if opts.ssh_host
277
277
 
278
278
  password_retry_cnt = 0
279
279
 
280
- unless batch_input
280
+ unless opts.batch_input
281
281
  print "SSH #{opts.ssh_user}#{opts.ssh_user ? '@' : ''}#{opts.ssh_host}..."
282
282
  $stdout.flush
283
283
  end
@@ -297,7 +297,7 @@ if opts.ssh_host
297
297
  ssh_enabled = false
298
298
  Signal.trap('INT', 'IGNORE')
299
299
  Signal.trap('TERM') do
300
- $stderr.puts 'Closing SSH connection...' unless batch_input
300
+ $stderr.puts 'Closing SSH connection...' unless opts.batch_input
301
301
  ssh_enabled = false
302
302
  end
303
303
  ssh_opts = {:timeout => 15}
@@ -313,7 +313,7 @@ if opts.ssh_host
313
313
  ssh = Net::SSH.start(opts.ssh_host, opts.ssh_user, ssh_opts)
314
314
  ssh_opts.delete(:password)
315
315
  ssh_enabled = true
316
- printf "connected (#{$$})..." unless batch_input
316
+ printf "connected (#{$$})..." unless opts.batch_input
317
317
  $stdout.flush
318
318
  rescue Net::SSH::AuthenticationFailed
319
319
  if 2 < password_retry_cnt
@@ -337,7 +337,7 @@ if opts.ssh_host
337
337
  ensure
338
338
  if ssh_enabled
339
339
  ssh.forward.local(opts.mysql_port, opts.mysql_host, opts.remote_mysql_port)
340
- unless batch_input
340
+ unless opts.batch_input
341
341
  puts(opts.verbose ? "ready (#{opts.mysql_port} => #{opts.remote_mysql_port})" : 'ready')
342
342
  end
343
343
  File.open(ipc_fn,'w'){|f| f.puts('ready')}
@@ -393,7 +393,7 @@ if opts.ssh_host
393
393
  opts.mysql_host = '127.0.0.1'
394
394
  end
395
395
 
396
- unless batch_input
396
+ unless opts.batch_input
397
397
  print "MySQL #{opts.mysql_user}@#{opts.remote_mysql_host}..."
398
398
  $stdout.flush
399
399
  end
@@ -403,7 +403,7 @@ begin
403
403
  MySQLResults.conn = Mysql.new(opts.mysql_host, opts.mysql_user, opts.mysql_password,
404
404
  MySQLResults.database_name, opts.mysql_port)
405
405
  MySQLResults.conn.reconnect = true
406
- puts 'connected' unless batch_input
406
+ puts 'connected' unless opts.batch_input
407
407
  rescue Mysql::Error => ex
408
408
  if ex.message.include?('Client does not support authentication')
409
409
  $stderr.puts "failed to connect to #{mysql_conn} mysql server: unknown credentials?"
@@ -440,10 +440,10 @@ cmd_thread = Thread.new do
440
440
  me[:shutdown] = false
441
441
  until me[:shutdown] do
442
442
  default_displayer = :display_by_column
443
- if batch_input
443
+ if opts.batch_input
444
444
  default_displayer = :display_by_batch if opts.batch_output
445
445
  me[:shutdown] = true # only run once
446
- input = batch_input
446
+ input = opts.batch_input
447
447
  else
448
448
  puts '',"[#{opts.mysql_user}@#{opts.ssh_host||opts.mysql_host}:#{MySQLResults.database_name}]"
449
449
  input = ''
data/example.rsqlrc CHANGED
@@ -1,42 +1,44 @@
1
1
  # -*- Mode: ruby -*-
2
2
 
3
- # This file is meant to be a working illustration of how RSQL might be
4
- # used and to show off various features of the application.
3
+ # = Getting Starting with RSQL
5
4
 
6
- # All examples below will use this temporary table. You will need to
7
- # "use" a database first before loading this file since it will need
8
- # to create this temporary table.
5
+ # This file is meant to be a working illustration of how RSQL might be used and
6
+ # to show off various features of the application.
7
+
8
+ # All examples below will use the following temporary table. You will need to
9
+ # "use" a database first before loading this file since it will need to create
10
+ # this temporary table.
9
11
  #
10
12
  @rsql_table = 'rsql_example'
11
13
 
12
- # To use this file, change directory to the one containing this file,
13
- # run rsql connecting to your MySQL server (run rsql with no arguments
14
- # for usage).
14
+ # To use this file, change directory to the one containing this file and run
15
+ # RSQL connecting to your MySQL server (run rsql with no arguments for
16
+ # usage--see rdoc-ref:README.rdoc for more details on command line parameters).
15
17
  #
16
18
  # rsql> .load 'example.rsqlrc';
17
19
 
18
- # After it's loaded try listing out all the registered recipes (along
19
- # with parameter notes and descriptions).
20
+ # After it's loaded try listing out all the registered recipes (along with
21
+ # parameter notes and descriptions).
20
22
  #
21
23
  # rsql> .list;
22
24
 
23
- # If you make changes to the example to try out new things (and please
24
- # do!), you can simply have the recipe file reloaded to have your
25
- # changes pulled in immediately without exiting your session.
25
+ # If you make changes to the example to try out new things (and please do!), you
26
+ # can simply have the recipe file reloaded to have your changes pulled in
27
+ # immediately without exiting your session.
26
28
  #
27
29
  # rsql> .reload;
28
30
 
29
31
  # Notice that any command issued starting with a period (.) results in
30
- # evaluation of Ruby. Thus, any valid Ruby syntax is applicable
31
- # following a period on a command.
32
+ # evaluation of Ruby. Thus, any valid Ruby syntax is applicable following a
33
+ # period on a command.
32
34
 
33
35
  ################################################################################
34
36
 
35
- # This type of registration is automatically invoked when this file is
36
- # loaded. Often, this is useful to run set up routines like setting
37
- # MySQL variables for different read levels (e.g. SET SESSION
38
- # TRANSACTION ISOLATION LEVEL READ COMMITTED). Any number of these may
39
- # be defined.
37
+ # Use of RSQL::EvalContext#register_init allows a block to be automatically
38
+ # invoked when this file is loaded. Often, this is useful to run set up routines
39
+ # like setting MySQL variables for different read levels (e.g. <b><tt>SET
40
+ # SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED</tt></b>). Any number of
41
+ # these may be defined.
40
42
  #
41
43
  # Here we are merely setting up the example table.
42
44
  #
@@ -48,15 +50,15 @@ CREATE TEMPORARY TABLE IF NOT EXISTS #{@rsql_table} (
48
50
  )
49
51
  }, :desc => 'Sets up example table for trying out RSQL.'
50
52
 
51
- # This recipe is simply building up a string with a single variable
52
- # interpolated into it (our table name). The string will then be used
53
- # as if typed at the command line.
53
+ # This next recipe is building up a string with a single variable interpolated
54
+ # into it (our table name) through RSQL::EvalContext#register. The string will
55
+ # then be used as if typed at the command line.
54
56
  #
55
57
  # rsql> .cleanup_example;
56
58
  #
57
- # In this case, we are simply dropping the table created by our
58
- # initialization recipe. If you do this, you'll need to call the
59
- # setup_example initialization recipe again before moving on.
59
+ # In this case, we are simply dropping the table created by our initialization
60
+ # recipe. If you do this, you'll need to call the <b><tt>setup_example</tt></b>
61
+ # initialization recipe again before moving on.
60
62
  #
61
63
  # rsql> .setup_example;
62
64
  #
@@ -64,15 +66,15 @@ register :cleanup_example, %q{
64
66
  DROP TEMPORARY TABLE IF EXISTS #{@rsql_table}
65
67
  }, :desc => 'Cleans up the example table.'
66
68
 
67
- # This is an example of a recipe that utilizes a Ruby block for
68
- # running code to generate the SQL we eventually return.
69
+ # This is an example of a recipe that utilizes a Ruby block for running code to
70
+ # generate the SQL we eventually return.
69
71
  #
70
72
  # Here we are just populating the table (if it isn't already).
71
73
  #
72
74
  # rsql> .fill_table;
73
75
  #
74
- # Notice the use of hexify and squeeze! methods available from
75
- # EvalContext.
76
+ # Notice the use of the RSQL::EvalContext#hexify and RSQL::EvalContext#squeeze!
77
+ # helper methods.
76
78
  #
77
79
  register :fill_table, :desc => 'Populate the example table.' do
78
80
  sql = ''
@@ -84,9 +86,8 @@ INSERT IGNORE INTO #{@rsql_table}
84
86
  stuff=#{hexify(rand((i+1)**100))};
85
87
  }
86
88
  end
87
- # one more that isn't randomly generated so we can reference it
88
- # later
89
- sql << %{
89
+ # one more that isn't randomly generated so we can reference it later
90
+ sql << %{
90
91
  INSERT IGNORE INTO #{@rsql_table}
91
92
  SET name='fancy9',
92
93
  value=#{9**9},
@@ -95,14 +96,13 @@ INSERT IGNORE INTO #{@rsql_table}
95
96
  squeeze!(sql)
96
97
  end
97
98
 
98
- # A very common reason for recipes is simply to add parameters to be
99
- # dropped in to our query. To facilitate this, simply declare one or
100
- # more variables immediately following the name of the recipe. Then
101
- # these values can be listed by embedded interpolation points into the
102
- # string (just as you would with any Ruby string).
99
+ # A very common reason for recipes is simply to add parameters to be dropped in
100
+ # to our query. To facilitate this, declare one or more variables immediately
101
+ # following the name of the recipe. These values can be listed by embedded
102
+ # interpolation points into the string (just as you would with any Ruby string).
103
103
  #
104
- # This call will simply return results only for those bigger than some
105
- # value passed in.
104
+ # This call will simply return results only for those bigger than some value
105
+ # passed in.
106
106
  #
107
107
  # rsql> .get_big_values 80000;
108
108
  #
@@ -110,19 +110,19 @@ register :get_big_values, :val, %q{
110
110
  SELECT name, value FROM #{@rsql_table} WHERE #{val} <= value
111
111
  }, :desc => 'Get values bigger than the one provided as an argument.'
112
112
 
113
- # Sometimes we make mistakes (never!). Normally, the command history
114
- # kept in RSQL only stores the last thing entered at the prompt--not
115
- # any query that the previous command may have generated and invoked.
116
- # When writing a recipe that generates a query that has an error
117
- # reported by MySQL, it is really handy to see the query.
113
+ # Sometimes we make mistakes (never!). Normally, the command history kept in
114
+ # RSQL only stores the last thing entered at the prompt--not any query that the
115
+ # previous command may have generated and invoked. When writing a recipe that
116
+ # generates a query that has an error reported by MySQL, it is really handy to
117
+ # see the generated SQL.
118
118
  #
119
- # Here's an example of a recipe that will fail. Run it and then hit the
120
- # "up arrow" key to see the previous command.
119
+ # Here's an example of a recipe that will fail. Run it and then hit the "up
120
+ # arrow" key to see the previous command.
121
121
  #
122
122
  # rsql> .bad_query;
123
123
  #
124
- # So the command in our history is the recipe and not the query. To
125
- # see the query the EvalContext has a recipe ready for us:
124
+ # So the command in our history is the recipe and not the query. To see the
125
+ # query the RSQL::EvalContext#history has a helper method ready for us:
126
126
  #
127
127
  # rsql> .history;
128
128
  #
@@ -130,21 +130,20 @@ register :bad_query, %q{
130
130
  SELECT name, value FROM #{@rsql_table} WHERE valu < 10000
131
131
  }, :desc => 'Make a query that will result in an error.'
132
132
 
133
- # After you have a table with content in it, you can run queries
134
- # against it and have the contents changed into something a little
135
- # more meaningful. For example, what if the values in our table were
136
- # bytes that we wanted to humanize? Try this command:
133
+ # After you have a table with content in it, you can run queries against it and
134
+ # have the contents changed into something a little more meaningful. For
135
+ # example, what if the values in our table were bytes that we wanted to
136
+ # humanize? Try this command:
137
137
  #
138
138
  # rsql> select name, value from rsql_example ! value => humanize_bytes;
139
139
  #
140
- # The humanize_bytes method is a helper in the EvalContext
141
- # class. There are several others available. Check out the rdoc for
142
- # details.
140
+ # The RSQL::EvalContext#humanize_bytes is another helper method. There are
141
+ # several others available. Check out the RSQL::EvalContext class for details.
143
142
  #
144
143
  # Additional mappings can be added, separated by commas.
145
144
  #
146
- # You can also declare these column mappings in your recipes, though
147
- # the syntax is slightly different, using Ruby symbols.
145
+ # You can also declare these column mappings in your recipes, though the syntax
146
+ # is slightly different, using Ruby symbols.
148
147
  #
149
148
  # rsql> .show_values_as_bytes;
150
149
  #
@@ -153,17 +152,16 @@ SELECT value FROM #{@rsql_table}
153
152
  }, 'value' => :humanize_bytes,
154
153
  :desc => 'Show values as humanized bytes.'
155
154
 
156
- # It is even possible to make up your own column mapping helpers. Just
157
- # create a Ruby method and reference it as a symbol mapped to whatever
158
- # column the helper is expecting for content. The return of the helper
159
- # will be replaced as the column entry's content. Your method is
160
- # called once for each value in the column from the results.
155
+ # It is even possible to make up your own column mapping helpers. Just create a
156
+ # Ruby method and reference it as a symbol mapped to whatever column the helper
157
+ # is expecting for content. The return of the helper will be replaced as the
158
+ # column entry's content. Your method is called once for each value in the
159
+ # column from the results.
161
160
  #
162
161
  # rsql> .show_pretty_names;
163
162
  #
164
- # Make sure if your method doesn't understand the content passed to it
165
- # that it just reflects it back out so you don't lose data when
166
- # printed.
163
+ # Make sure if your method doesn't understand the content passed to it that it
164
+ # just reflects it back out so you don't lose data when printed.
167
165
  #
168
166
  def pretty_names(name)
169
167
  if m = name.match(/^(\w+)(\d+)$/)
@@ -178,22 +176,22 @@ SELECT name FROM #{@rsql_table}
178
176
  }, 'name' => :pretty_names,
179
177
  :desc => 'Show names separated to be more readable.'
180
178
 
181
- # It's also possible to work with the full set of query results in a
182
- # recipe. This can be useful if there is some coordination necessary
183
- # across multiple columns to result in some new kind of report. Much
184
- # like a shell's ability to pipe output from one command to the next,
185
- # RSQL takes a similar approach. Try this:
179
+ # It's also possible to work with the full set of query results in a recipe.
180
+ # This can be useful if there is some coordination necessary across multiple
181
+ # columns to result in some new kind of report. Much like a shell's ability to
182
+ # pipe output from one command to the next, RSQL takes a similar approach. Try
183
+ # this:
186
184
  #
187
185
  # rsql> select name, value from rsql_example | p @results;
188
186
  #
189
- # The EvalContext manages the results from a previous query in the
190
- # @results member variable accessible by any Ruby recipe code. This is
191
- # an instance of the MySQLResults class. Below we make use of the
192
- # each_hash method to walk over all rows. There are other helpful
193
- # routines available as well that are documented in rdoc.
187
+ # The RSQL::EvalContext class manages the results from a previous query in the
188
+ # <b><tt>@results</tt></b> member variable accessible by any Ruby recipe
189
+ # code. This is an instance of the RSQL::MySQLResults class. Below we make use
190
+ # of the RSQL::MySQLResults#each_hash method to walk over all rows. There are
191
+ # other helpful routines available.
194
192
  #
195
- # Here's an example that writes a simple report of the data we are
196
- # working with. To try this out, enter the following at the prompt:
193
+ # Here's an example that writes a simple report of the data we are working
194
+ # with. To try this out, enter the following at the prompt:
197
195
  #
198
196
  # rsql> select name, value from rsql_example | to_report;
199
197
  #
@@ -210,19 +208,17 @@ register :to_report, :desc => 'Report on a count of small and big values.' do
210
208
  puts "There are #{small_cnt} small values and #{big_cnt} big values."
211
209
  end
212
210
 
213
- # There may be other moments where it's necessary to take arguments,
214
- # say if we want to process results and keep our data around in a
215
- # file.
211
+ # There may be other moments where it's necessary to take arguments, say if we
212
+ # want to process results and keep our data around in a file.
216
213
  #
217
214
  # rsql> select name, value from rsql_example | save_values 'myobj';
218
215
  #
219
- # After running this, a myobj.yml file should be created in the local
220
- # directory containing all the content from the query. To accomplish
221
- # this, the use of EvalContext's safe_save method is invoked which
222
- # serializes our object so that we may later decided to run some post
223
- # processing on the content.
216
+ # After running this, a <b><tt>myobj.yml</tt></b> file should be created in the
217
+ # local directory containing all the content from the query. To accomplish this,
218
+ # the RSQL::EvalContext#safe_save method is invoked which serializes our object
219
+ # so that we may later decided to run some post processing on the content.
224
220
  #
225
- # Inspect the YAML content written out:
221
+ # Inspect the YAML[http://www.yaml.org/] content written out:
226
222
  #
227
223
  # rsql> .puts IO.read('myobj.yml');
228
224
  #
@@ -234,8 +230,8 @@ register :save_values, :desc => 'Save results from a query into a file.' do |fn|
234
230
  safe_save(myobj, fn)
235
231
  end
236
232
 
237
- # Dealing with variable arguments is pretty straightforward as well,
238
- # but with a little syntactic twist.
233
+ # Dealing with variable arguments is pretty straightforward as well, but with a
234
+ # little syntactic twist.
239
235
  #
240
236
  # rsql> .find_names 'fancy3', 'fancy8';
241
237
  #
@@ -247,14 +243,14 @@ SELECT name, value
247
243
  WHERE name IN (#{names.collect{|n| "'#{n}'"}.join(',')})
248
244
  }, :desc => 'Find names from example table.'
249
245
 
250
- # Sometimes it just isn't enough to be able to rely on generating SQL
251
- # queries and piping into handlers. Sometimes we just need to roll up
252
- # our sleeves and run queries directly so we can start processing
253
- # results and dealing with presentation all on our own. That's where
254
- # EvalContext's query helper comes in handy.
246
+ # Sometimes it just isn't enough to be able to rely on generating SQL queries
247
+ # and piping into handlers. Sometimes we just need to roll up our sleeves and
248
+ # run queries directly so we can start processing results and dealing with
249
+ # presentation all on our own. That's where the RSQL::EvalContext#query helper
250
+ # comes in handy.
255
251
  #
256
- # The intention here is to just create a series of sentences out of
257
- # two separate queries.
252
+ # The intention here is to just create a series of sentences out of two separate
253
+ # queries.
258
254
  #
259
255
  # rsql> .show_sentences;
260
256
  #
@@ -266,15 +262,14 @@ register :show_sentences, :desc => 'Show results as sentences.' do
266
262
  end
267
263
  end
268
264
 
269
- # The MySQLResults class built in to RSQL handles binary content
270
- # gracefully, automatically converting it to something a little nicer
271
- # to our consoles than just dumping it. It converts it into a
272
- # hexadecimal string.
265
+ # The RSQL::MySQLResults class built in to RSQL handles binary content
266
+ # gracefully, automatically converting it to something a little nicer to our
267
+ # consoles than just dumping it. It converts it into a hexadecimal string.
273
268
  #
274
269
  # rsql> SELECT stuff FROM rsql_example;
275
270
  #
276
- # The default is to limit the hex strings to 32 "bytes" reported. This
277
- # can be configured any time by setting the @hexstr_limit.
271
+ # The default is to limit the hex strings to 32 "bytes" reported. This can be
272
+ # configured any time by setting the <b><tt>@hexstr_limit</tt></b>.
278
273
  #
279
274
  # RSQL makes querying for hex strings from within a recipe easy too.
280
275
  #
@@ -285,7 +280,7 @@ SELECT * FROM #{@rsql_table} WHERE stuff=#{hexify stuff}
285
280
  }, :desc => 'Find some hex stuff.'
286
281
 
287
282
  # There are many other things to try out left as an "exercise for the
288
- # reader". Browsing the rdoc for EvalContext and MySQLResults would be
289
- # an excellent start.
283
+ # reader". Browsing the RSQL::EvalContext and RSQL::MySQLResults classes would
284
+ # be an excellent start.
290
285
 
291
286
  # vi: set filetype=ruby
@@ -0,0 +1,286 @@
1
+
2
+
3
+ = Getting Starting with RSQL
4
+
5
+ This file is meant to be a working illustration of how RSQL might be used and
6
+ to show off various features of the application.
7
+
8
+ All examples below will use the following temporary table. You will need to
9
+ "use" a database first before loading this file since it will need to create
10
+ this temporary table.
11
+
12
+ @rsql_table = 'rsql_example'
13
+
14
+ To use this file, change directory to the one containing this file and run
15
+ RSQL connecting to your MySQL server (run rsql with no arguments for
16
+ usage--see rdoc-ref:README.rdoc for more details on command line parameters).
17
+
18
+ <tt>rsql> .load 'example.rsqlrc';</tt>
19
+
20
+ After it's loaded try listing out all the registered recipes (along with
21
+ parameter notes and descriptions).
22
+
23
+ <tt>rsql> .list;</tt>
24
+
25
+ If you make changes to the example to try out new things (and please do!), you
26
+ can simply have the recipe file reloaded to have your changes pulled in
27
+ immediately without exiting your session.
28
+
29
+ <tt>rsql> .reload;</tt>
30
+
31
+ Notice that any command issued starting with a period (.) results in
32
+ evaluation of Ruby. Thus, any valid Ruby syntax is applicable following a
33
+ period on a command.
34
+
35
+ ---
36
+
37
+ Use of RSQL::EvalContext#register_init allows a block to be automatically
38
+ invoked when this file is loaded. Often, this is useful to run set up routines
39
+ like setting MySQL variables for different read levels (e.g. <b><tt>SET
40
+ SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED</tt></b>). Any number of
41
+ these may be defined.
42
+
43
+ Here we are merely setting up the example table.
44
+
45
+ register_init :setup_example, %q{
46
+ CREATE TEMPORARY TABLE IF NOT EXISTS #{@rsql_table} (
47
+ name VARCHAR(100),
48
+ value INT(11),
49
+ stuff BLOB
50
+ )
51
+ }, :desc => 'Sets up example table for trying out RSQL.'
52
+
53
+ This next recipe is building up a string with a single variable interpolated
54
+ into it (our table name) through RSQL::EvalContext#register. The string will
55
+ then be used as if typed at the command line.
56
+
57
+ <tt>rsql> .cleanup_example;</tt>
58
+
59
+ In this case, we are simply dropping the table created by our initialization
60
+ recipe. If you do this, you'll need to call the <b><tt>setup_example</tt></b>
61
+ initialization recipe again before moving on.
62
+
63
+ <tt>rsql> .setup_example;</tt>
64
+
65
+ register :cleanup_example, %q{
66
+ DROP TEMPORARY TABLE IF EXISTS #{@rsql_table}
67
+ }, :desc => 'Cleans up the example table.'
68
+
69
+ This is an example of a recipe that utilizes a Ruby block for running code to
70
+ generate the SQL we eventually return.
71
+
72
+ Here we are just populating the table (if it isn't already).
73
+
74
+ <tt>rsql> .fill_table;</tt>
75
+
76
+ Notice the use of the RSQL::EvalContext#hexify and RSQL::EvalContext#squeeze!
77
+ helper methods.
78
+
79
+ register :fill_table, :desc => 'Populate the example table.' do
80
+ sql = ''
81
+ 9.times do |i|
82
+ sql << %{
83
+ INSERT IGNORE INTO #{@rsql_table}
84
+ SET name='fancy#{i}',
85
+ value=#{i**i},
86
+ stuff=#{hexify(rand((i+1)**100))};
87
+ }
88
+ end
89
+ # one more that isn't randomly generated so we can reference it later
90
+ sql << %{
91
+ INSERT IGNORE INTO #{@rsql_table}
92
+ SET name='fancy9',
93
+ value=#{9**9},
94
+ stuff=0x1234567891234567891234567890;
95
+ }
96
+ squeeze!(sql)
97
+ end
98
+
99
+ A very common reason for recipes is simply to add parameters to be dropped in
100
+ to our query. To facilitate this, declare one or more variables immediately
101
+ following the name of the recipe. These values can be listed by embedded
102
+ interpolation points into the string (just as you would with any Ruby string).
103
+
104
+ This call will simply return results only for those bigger than some value
105
+ passed in.
106
+
107
+ <tt>rsql> .get_big_values 80000;</tt>
108
+
109
+ register :get_big_values, :val, %q{
110
+ SELECT name, value FROM #{@rsql_table} WHERE #{val} <= value
111
+ }, :desc => 'Get values bigger than the one provided as an argument.'
112
+
113
+ Sometimes we make mistakes (never!). Normally, the command history kept in
114
+ RSQL only stores the last thing entered at the prompt--not any query that the
115
+ previous command may have generated and invoked. When writing a recipe that
116
+ generates a query that has an error reported by MySQL, it is really handy to
117
+ see the generated SQL.
118
+
119
+ Here's an example of a recipe that will fail. Run it and then hit the "up
120
+ arrow" key to see the previous command.
121
+
122
+ <tt>rsql> .bad_query;</tt>
123
+
124
+ So the command in our history is the recipe and not the query. To see the
125
+ query the RSQL::EvalContext#history has a helper method ready for us:
126
+
127
+ <tt>rsql> .history;</tt>
128
+
129
+ register :bad_query, %q{
130
+ SELECT name, value FROM #{@rsql_table} WHERE valu < 10000
131
+ }, :desc => 'Make a query that will result in an error.'
132
+
133
+ After you have a table with content in it, you can run queries against it and
134
+ have the contents changed into something a little more meaningful. For
135
+ example, what if the values in our table were bytes that we wanted to
136
+ humanize? Try this command:
137
+
138
+ <tt>rsql> select name, value from rsql_example ! value => humanize_bytes;</tt>
139
+
140
+ The RSQL::EvalContext#humanize_bytes is another helper method. There are
141
+ several others available. Check out the RSQL::EvalContext class for details.
142
+
143
+ Additional mappings can be added, separated by commas.
144
+
145
+ You can also declare these column mappings in your recipes, though the syntax
146
+ is slightly different, using Ruby symbols.
147
+
148
+ <tt>rsql> .show_values_as_bytes;</tt>
149
+
150
+ register :show_values_as_bytes, %q{
151
+ SELECT value FROM #{@rsql_table}
152
+ }, 'value' => :humanize_bytes,
153
+ :desc => 'Show values as humanized bytes.'
154
+
155
+ It is even possible to make up your own column mapping helpers. Just create a
156
+ Ruby method and reference it as a symbol mapped to whatever column the helper
157
+ is expecting for content. The return of the helper will be replaced as the
158
+ column entry's content. Your method is called once for each value in the
159
+ column from the results.
160
+
161
+ <tt>rsql> .show_pretty_names;</tt>
162
+
163
+ Make sure if your method doesn't understand the content passed to it that it
164
+ just reflects it back out so you don't lose data when printed.
165
+
166
+ def pretty_names(name)
167
+ if m = name.match(/^(\w+)(\d+)$/)
168
+ "#{m[1]} (#{m[2]})"
169
+ else
170
+ name
171
+ end
172
+ end
173
+
174
+ register :show_pretty_names, %q{
175
+ SELECT name FROM #{@rsql_table}
176
+ }, 'name' => :pretty_names,
177
+ :desc => 'Show names separated to be more readable.'
178
+
179
+ It's also possible to work with the full set of query results in a recipe.
180
+ This can be useful if there is some coordination necessary across multiple
181
+ columns to result in some new kind of report. Much like a shell's ability to
182
+ pipe output from one command to the next, RSQL takes a similar approach. Try
183
+ this:
184
+
185
+ <tt>rsql> select name, value from rsql_example | p @results;</tt>
186
+
187
+ The RSQL::EvalContext class manages the results from a previous query in the
188
+ <b><tt>@results</tt></b> member variable accessible by any Ruby recipe
189
+ code. This is an instance of the RSQL::MySQLResults class. Below we make use
190
+ of the RSQL::MySQLResults#each_hash method to walk over all rows. There are
191
+ other helpful routines available.
192
+
193
+ Here's an example that writes a simple report of the data we are working
194
+ with. To try this out, enter the following at the prompt:
195
+
196
+ <tt>rsql> select name, value from rsql_example | to_report;</tt>
197
+
198
+ register :to_report, :desc => 'Report on a count of small and big values.' do
199
+ small_cnt = 0
200
+ big_cnt = 0
201
+ @results.each_hash do |row|
202
+ if row['value'].to_i < 10000
203
+ small_cnt +=1
204
+ else
205
+ big_cnt += 1
206
+ end
207
+ end
208
+ puts "There are #{small_cnt} small values and #{big_cnt} big values."
209
+ end
210
+
211
+ There may be other moments where it's necessary to take arguments, say if we
212
+ want to process results and keep our data around in a file.
213
+
214
+ <tt>rsql> select name, value from rsql_example | save_values 'myobj';</tt>
215
+
216
+ After running this, a <b><tt>myobj.yml</tt></b> file should be created in the
217
+ local directory containing all the content from the query. To accomplish this,
218
+ the RSQL::EvalContext#safe_save method is invoked which serializes our object
219
+ so that we may later decided to run some post processing on the content.
220
+
221
+ Inspect the YAML[http://www.yaml.org/] content written out:
222
+
223
+ <tt>rsql> .puts IO.read('myobj.yml');</tt>
224
+
225
+ register :save_values, :desc => 'Save results from a query into a file.' do |fn|
226
+ myobj = {}
227
+ @results.each_hash do |row|
228
+ myobj[row['name']] = row['value']
229
+ end
230
+ safe_save(myobj, fn)
231
+ end
232
+
233
+ Dealing with variable arguments is pretty straightforward as well, but with a
234
+ little syntactic twist.
235
+
236
+ <tt>rsql> .find_names 'fancy3', 'fancy8';</tt>
237
+
238
+ Here we simply expand the arguments.
239
+
240
+ register :find_names, :'*names', %q{
241
+ SELECT name, value
242
+ FROM #{@rsql_table}
243
+ WHERE name IN (#{names.collect{|n| "'#{n}'"}.join(',')})
244
+ }, :desc => 'Find names from example table.'
245
+
246
+ Sometimes it just isn't enough to be able to rely on generating SQL queries
247
+ and piping into handlers. Sometimes we just need to roll up our sleeves and
248
+ run queries directly so we can start processing results and dealing with
249
+ presentation all on our own. That's where the RSQL::EvalContext#query helper
250
+ comes in handy.
251
+
252
+ The intention here is to just create a series of sentences out of two separate
253
+ queries.
254
+
255
+ <tt>rsql> .show_sentences;</tt>
256
+
257
+ register :show_sentences, :desc => 'Show results as sentences.' do
258
+ query("SELECT name FROM #{@rsql_table}").each_hash do |nrow|
259
+ name = nrow['name']
260
+ vals = query("SELECT value FROM #{@rsql_table} WHERE name='#{name}'")
261
+ puts "The #{name} has #{vals[0]['value']} fanciness levels."
262
+ end
263
+ end
264
+
265
+ The RSQL::MySQLResults class built in to RSQL handles binary content
266
+ gracefully, automatically converting it to something a little nicer to our
267
+ consoles than just dumping it. It converts it into a hexadecimal string.
268
+
269
+ <tt>rsql> SELECT stuff FROM rsql_example;</tt>
270
+
271
+ The default is to limit the hex strings to 32 "bytes" reported. This can be
272
+ configured any time by setting the <b><tt>@hexstr_limit</tt></b>.
273
+
274
+ RSQL makes querying for hex strings from within a recipe easy too.
275
+
276
+ <tt>rsql> .find_stuff 0x1234567891234567891234567890;</tt>
277
+
278
+ register :find_stuff, :stuff, %q{
279
+ SELECT * FROM #{@rsql_table} WHERE stuff=#{hexify stuff}
280
+ }, :desc => 'Find some hex stuff.'
281
+
282
+ There are many other things to try out left as an "exercise for the
283
+ reader". Browsing the RSQL::EvalContext and RSQL::MySQLResults classes would
284
+ be an excellent start.
285
+
286
+
data/lib/rsql.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  # A module encapsulating classes to manage MySQLResults and process
2
2
  # Commands using an EvalContext for handling recipes.
3
3
  #
4
+ # See the rdoc-ref:example.rsqlrc.rdoc file for a simple tutorial and usage
5
+ # information.
6
+ #
4
7
  module RSQL
5
- VERSION = '0.2.8'
8
+ VERSION = '0.2.9'
6
9
 
7
10
  require 'rsql/mysql_results'
8
11
  require 'rsql/eval_context'
@@ -63,7 +63,7 @@ module RSQL
63
63
  'Show short syntax help.'),
64
64
  :grep => Registration.new('grep', [], {},
65
65
  method(:grep),
66
- 'grep',
66
+ 'grep(string_or_regexp, *options)',
67
67
  'Show results when regular expression matches any part of the content.'),
68
68
  :reload => Registration.new('reload', [], {},
69
69
  method(:reload),
@@ -71,7 +71,7 @@ module RSQL
71
71
  'Reload the rsqlrc file.'),
72
72
  :desc => Registration.new('desc', [], {},
73
73
  method(:desc),
74
- 'desc',
74
+ 'desc(name)',
75
75
  'Describe the content of a recipe.'),
76
76
  :history => Registration.new('history', [], {},
77
77
  method(:history),
@@ -79,7 +79,7 @@ module RSQL
79
79
  'Print recent queries made (request a count or use :all for entire list).'),
80
80
  :set_max_rows => Registration.new('set_max_rows', [], {},
81
81
  Proc.new{|r| MySQLResults.max_rows = r},
82
- 'set_max_rows',
82
+ 'set_max_rows(max)',
83
83
  'Set the maximum number of rows to process.'),
84
84
  :max_rows => Registration.new('max_rows', [], {},
85
85
  Proc.new{MySQLResults.max_rows},
@@ -334,59 +334,62 @@ module RSQL
334
334
  return nil
335
335
  end
336
336
 
337
+ # Used by params() and desc() to find where a block begins.
338
+ #
339
+ def locate_block_start(name, io, lineno, ending=nil, source=nil)
340
+ i = 0
341
+ param_line = ''
342
+ params = nil
343
+
344
+ while line = io.gets
345
+ i += 1
346
+ next if i < lineno
347
+ source << line if source
348
+
349
+ # give up if no start found within 20 lines
350
+ break if lineno + 20 < i
351
+ if m = line.match(/(\{|do\b)(.*)$/)
352
+ if ending
353
+ ending << (m[1] == '{' ? '\}' : 'end')
354
+ end
355
+ # adjust line to be the remainder after the start
356
+ param_line = m[2]
357
+ break
358
+ end
359
+ end
360
+
361
+ if m = param_line.match(/^\s*\|([^\|]*)\|/)
362
+ return "(#{m[1]})"
363
+ else
364
+ return nil
365
+ end
366
+ end
367
+
337
368
  # Attempt to locate the parameters of a given block by
338
369
  # searching its source.
339
370
  #
340
371
  def params(name, block)
341
- params = ''
372
+ params = nil
342
373
 
343
- if block.arity != 0 && block.arity != -1 &&
344
- block.inspect.match(/@(.+):(\d+)>$/)
374
+ if block.arity != 0 && block.inspect.match(/@(.+):(\d+)>$/)
345
375
  fn = $1
346
376
  lineno = $2.to_i
347
377
 
348
378
  if fn == '(eval)'
349
379
  $stderr.puts "refusing to search an eval block for :#{name}"
350
- return params
380
+ return ''
351
381
  end
352
382
 
353
383
  File.open(fn) do |f|
354
- i = 0
355
- found = false
356
- while line = f.gets
357
- i += 1
358
- next if i < lineno
359
-
360
- unless found
361
- # give up if no start found within 20
362
- # lines
363
- break if lineno + 20 < i
364
- if m = line.match(/(\{|do\b)(.*)$/)
365
- # adjust line to be the remainder
366
- # after the start
367
- line = m[2]
368
- found = true
369
- else
370
- next
371
- end
372
- end
373
-
374
- if m = line.match(/^\s*\|([^\|]*)\|/)
375
- params = "(#{m[1]})"
376
- break
377
- end
378
-
379
- # if the params aren't here then we'd
380
- # better only have whitespace otherwise
381
- # this block doesn't have params...even
382
- # though arity says it should
383
- next if line.match(/^\s*$/)
384
- $stderr.puts "unable to locate params for :#{name}"
385
- break
386
- end
384
+ params = locate_block_start(name, f, lineno)
387
385
  end
388
386
  end
389
387
 
388
+ if params.nil?
389
+ $stderr.puts "unable to locate params for :#{name}" if @verbose
390
+ return ''
391
+ end
392
+
390
393
  return params
391
394
  end
392
395
 
@@ -428,23 +431,13 @@ module RSQL
428
431
 
429
432
  File.open(fn) do |f|
430
433
  source = ''
431
- i = 0
432
- ending = nil
433
- found = false
434
+ ending = ''
435
+
436
+ locate_block_start(sym, f, lineno, ending, source)
437
+ break if ending.empty?
434
438
 
435
439
  while line = f.gets
436
- i += 1
437
- next unless ending || i == lineno
438
440
  source << line
439
- unless ending
440
- unless m = line.match(/\{|do\b/)
441
- $stderr.puts "unable to locate block beginning at #{fn}:#{lineno}"
442
- return
443
- end
444
- ending = m[0] == '{' ? '\}' : 'end'
445
- next
446
- end
447
-
448
441
  if m = line.match(/^#{ending}/)
449
442
  found = true
450
443
  break
@@ -503,7 +496,8 @@ EOF
503
496
  end
504
497
 
505
498
  # Provide a helper utility in the event a registered method would
506
- # like to make its own queries.
499
+ # like to make its own queries. See MySQLResults.query for more
500
+ # details regarding the other arguments available.
507
501
  #
508
502
  def query(content, *args) # :doc:
509
503
  MySQLResults.query(content, self, *args)
@@ -512,17 +506,17 @@ EOF
512
506
  # Show the most recent queries made to the MySQL server in this
513
507
  # session. Default is to show the last one.
514
508
  #
515
- def history(cnt=1)
509
+ def history(cnt=1) # :doc:
516
510
  if h = MySQLResults.history(cnt)
517
511
  h.each{|q| puts '', q}
518
512
  end
519
513
  nil
520
514
  end
521
515
 
522
- # Call MySQLResults' grep to remove (or show) only those lines that
516
+ # Call MySQLResults#grep to remove (or show) only those lines that
523
517
  # have content matching the patterrn.
524
518
  #
525
- def grep(*args)
519
+ def grep(*args) # :doc:
526
520
  if @results.grep(*args)
527
521
  @results
528
522
  else
@@ -24,7 +24,7 @@
24
24
  #
25
25
  require 'mysqlplus'
26
26
 
27
- class Mysql
27
+ class Mysql # :nodoc:
28
28
  alias :query :async_query
29
29
  end
30
30
 
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: 7
4
+ hash: 5
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 8
10
- version: 0.2.8
9
+ - 9
10
+ version: 0.2.9
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: 2012-02-13 00:00:00 Z
18
+ date: 2012-02-15 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: net-ssh
@@ -116,6 +116,7 @@ extensions: []
116
116
  extra_rdoc_files:
117
117
  - README.rdoc
118
118
  - LICENSE
119
+ - example.rsqlrc.rdoc
119
120
  files:
120
121
  - LICENSE
121
122
  - README.rdoc
@@ -129,6 +130,7 @@ files:
129
130
  - test/test_commands.rb
130
131
  - test/test_eval_context.rb
131
132
  - test/test_mysql_results.rb
133
+ - example.rsqlrc.rdoc
132
134
  homepage: https://rubygems.org/gems/rsql
133
135
  licenses: []
134
136
 
@@ -167,5 +169,7 @@ rubygems_version: 1.8.16
167
169
  signing_key:
168
170
  specification_version: 3
169
171
  summary: Ruby-based MySQL command line with recipes.
170
- test_files: []
171
-
172
+ test_files:
173
+ - test/test_commands.rb
174
+ - test/test_eval_context.rb
175
+ - test/test_mysql_results.rb