rsql 0.2.8 → 0.2.9

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/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