pg 0.13.2-x86-mingw32 → 0.14.0.pre.353-x86-mingw32
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/ChangeLog +230 -1
- data/History.rdoc +28 -0
- data/Manifest.txt +8 -0
- data/Rakefile +8 -2
- data/Rakefile.cross +11 -4
- data/ext/extconf.rb +7 -0
- data/ext/pg.c +76 -2
- data/ext/pg.h +2 -2
- data/ext/pg_connection.c +196 -81
- data/ext/pg_result.c +77 -58
- data/lib/1.8/pg_ext.so +0 -0
- data/lib/1.9/pg_ext.so +0 -0
- data/lib/pg.rb +1 -1
- data/lib/pg/connection.rb +7 -0
- data/sample/async_api.rb +2 -0
- data/sample/check_conn.rb +21 -0
- data/sample/disk_usage_report.rb +186 -0
- data/sample/issue-119.rb +94 -0
- data/sample/minimal-testcase.rb +17 -0
- data/sample/pg_statistics.rb +294 -0
- data/sample/replication_monitor.rb +231 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +320 -0
- data/spec/lib/helpers.rb +6 -1
- data/spec/pg/connection_spec.rb +205 -141
- data/spec/pg/result_spec.rb +18 -6
- data/spec/pg_spec.rb +9 -0
- metadata +50 -34
data/ext/pg_result.c
CHANGED
@@ -21,32 +21,38 @@ static PGresult* pgresult_get( VALUE );
|
|
21
21
|
* Result constructor
|
22
22
|
*/
|
23
23
|
VALUE
|
24
|
-
pg_new_result(PGresult *result,
|
24
|
+
pg_new_result(PGresult *result, VALUE rb_pgconn)
|
25
25
|
{
|
26
|
+
PGconn *conn = pg_get_pgconn( rb_pgconn );
|
26
27
|
VALUE val = Data_Wrap_Struct(rb_cPGresult, NULL, pgresult_gc_free, result);
|
27
28
|
#ifdef M17N_SUPPORTED
|
28
29
|
rb_encoding *enc = pg_conn_enc_get( conn );
|
29
30
|
ENCODING_SET( val, rb_enc_to_index(enc) );
|
30
31
|
#endif
|
31
32
|
|
33
|
+
rb_iv_set( val, "@connection", rb_pgconn );
|
34
|
+
|
32
35
|
return val;
|
33
36
|
}
|
34
37
|
|
35
38
|
/*
|
36
|
-
*
|
37
|
-
*
|
39
|
+
* call-seq:
|
40
|
+
* res.result -> nil
|
41
|
+
*
|
42
|
+
* Raises appropriate exception if PG::Result is in a bad state.
|
38
43
|
*/
|
39
|
-
|
40
|
-
|
44
|
+
VALUE
|
45
|
+
pg_result_check( VALUE self )
|
41
46
|
{
|
42
47
|
VALUE error, exception;
|
48
|
+
VALUE rb_pgconn = rb_iv_get( self, "@connection" );
|
43
49
|
PGconn *conn = pg_get_pgconn(rb_pgconn);
|
44
50
|
PGresult *result;
|
45
51
|
#ifdef M17N_SUPPORTED
|
46
52
|
rb_encoding *enc = pg_conn_enc_get( conn );
|
47
53
|
#endif
|
48
54
|
|
49
|
-
Data_Get_Struct(
|
55
|
+
Data_Get_Struct(self, PGresult, result);
|
50
56
|
|
51
57
|
if(result == NULL)
|
52
58
|
{
|
@@ -59,9 +65,12 @@ pg_check_result(VALUE rb_pgconn, VALUE rb_pgresult)
|
|
59
65
|
case PGRES_TUPLES_OK:
|
60
66
|
case PGRES_COPY_OUT:
|
61
67
|
case PGRES_COPY_IN:
|
68
|
+
#ifdef HAVE_CONST_PGRES_COPY_BOTH
|
69
|
+
case PGRES_COPY_BOTH:
|
70
|
+
#endif
|
62
71
|
case PGRES_EMPTY_QUERY:
|
63
72
|
case PGRES_COMMAND_OK:
|
64
|
-
return;
|
73
|
+
return Qnil;
|
65
74
|
case PGRES_BAD_RESPONSE:
|
66
75
|
case PGRES_FATAL_ERROR:
|
67
76
|
case PGRES_NONFATAL_ERROR:
|
@@ -77,10 +86,11 @@ pg_check_result(VALUE rb_pgconn, VALUE rb_pgresult)
|
|
77
86
|
#endif
|
78
87
|
exception = rb_exc_new3( rb_ePGerror, error );
|
79
88
|
rb_iv_set( exception, "@connection", rb_pgconn );
|
80
|
-
rb_iv_set( exception, "@result",
|
89
|
+
rb_iv_set( exception, "@result", self );
|
81
90
|
rb_exc_raise( exception );
|
82
91
|
|
83
|
-
|
92
|
+
/* Not reached */
|
93
|
+
return Qnil;
|
84
94
|
}
|
85
95
|
|
86
96
|
|
@@ -94,7 +104,7 @@ pg_check_result(VALUE rb_pgconn, VALUE rb_pgresult)
|
|
94
104
|
* call-seq:
|
95
105
|
* res.clear() -> nil
|
96
106
|
*
|
97
|
-
* Clears the
|
107
|
+
* Clears the PG::Result object as the result of the query.
|
98
108
|
*/
|
99
109
|
VALUE
|
100
110
|
pg_result_clear(VALUE self)
|
@@ -135,7 +145,7 @@ pgresult_get(VALUE self)
|
|
135
145
|
|
136
146
|
/********************************************************************
|
137
147
|
*
|
138
|
-
* Document-class:
|
148
|
+
* Document-class: PG::Result
|
139
149
|
*
|
140
150
|
* The class to represent the query result tuples (rows).
|
141
151
|
* An instance of this class is created as the result of every query.
|
@@ -153,7 +163,7 @@ pgresult_get(VALUE self)
|
|
153
163
|
*/
|
154
164
|
|
155
165
|
/**************************************************************************
|
156
|
-
*
|
166
|
+
* PG::Result INSTANCE METHODS
|
157
167
|
**************************************************************************/
|
158
168
|
|
159
169
|
/*
|
@@ -229,20 +239,20 @@ pgresult_error_message(VALUE self)
|
|
229
239
|
*
|
230
240
|
* begin
|
231
241
|
* conn.exec( "SELECT * FROM nonexistant_table" )
|
232
|
-
* rescue
|
242
|
+
* rescue PG::Error => err
|
233
243
|
* p [
|
234
|
-
* result.error_field(
|
235
|
-
* result.error_field(
|
236
|
-
* result.error_field(
|
237
|
-
* result.error_field(
|
238
|
-
* result.error_field(
|
239
|
-
* result.error_field(
|
240
|
-
* result.error_field(
|
241
|
-
* result.error_field(
|
242
|
-
* result.error_field(
|
243
|
-
* result.error_field(
|
244
|
-
* result.error_field(
|
245
|
-
* result.error_field(
|
244
|
+
* result.error_field( PG::Result::PG_DIAG_SEVERITY ),
|
245
|
+
* result.error_field( PG::Result::PG_DIAG_SQLSTATE ),
|
246
|
+
* result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY ),
|
247
|
+
* result.error_field( PG::Result::PG_DIAG_MESSAGE_DETAIL ),
|
248
|
+
* result.error_field( PG::Result::PG_DIAG_MESSAGE_HINT ),
|
249
|
+
* result.error_field( PG::Result::PG_DIAG_STATEMENT_POSITION ),
|
250
|
+
* result.error_field( PG::Result::PG_DIAG_INTERNAL_POSITION ),
|
251
|
+
* result.error_field( PG::Result::PG_DIAG_INTERNAL_QUERY ),
|
252
|
+
* result.error_field( PG::Result::PG_DIAG_CONTEXT ),
|
253
|
+
* result.error_field( PG::Result::PG_DIAG_SOURCE_FILE ),
|
254
|
+
* result.error_field( PG::Result::PG_DIAG_SOURCE_LINE ),
|
255
|
+
* result.error_field( PG::Result::PG_DIAG_SOURCE_FUNCTION ),
|
246
256
|
* ]
|
247
257
|
* end
|
248
258
|
*
|
@@ -492,7 +502,7 @@ pgresult_fsize(VALUE self, VALUE index)
|
|
492
502
|
static VALUE
|
493
503
|
pgresult_getvalue(VALUE self, VALUE tup_num, VALUE field_num)
|
494
504
|
{
|
495
|
-
VALUE
|
505
|
+
VALUE val;
|
496
506
|
PGresult *result;
|
497
507
|
int i = NUM2INT(tup_num);
|
498
508
|
int j = NUM2INT(field_num);
|
@@ -506,10 +516,19 @@ pgresult_getvalue(VALUE self, VALUE tup_num, VALUE field_num)
|
|
506
516
|
}
|
507
517
|
if(PQgetisnull(result, i, j))
|
508
518
|
return Qnil;
|
509
|
-
|
519
|
+
val = rb_tainted_str_new(PQgetvalue(result, i, j),
|
510
520
|
PQgetlength(result, i, j));
|
511
|
-
|
512
|
-
|
521
|
+
|
522
|
+
#ifdef M17N_SUPPORTED
|
523
|
+
/* associate client encoding for text format only */
|
524
|
+
if ( 0 == PQfformat(result, j) ) {
|
525
|
+
ASSOCIATE_INDEX( val, self );
|
526
|
+
} else {
|
527
|
+
rb_enc_associate( val, rb_ascii8bit_encoding() );
|
528
|
+
}
|
529
|
+
#endif
|
530
|
+
|
531
|
+
return val;
|
513
532
|
}
|
514
533
|
|
515
534
|
/*
|
@@ -612,7 +631,7 @@ pgresult_cmd_status(VALUE self)
|
|
612
631
|
*
|
613
632
|
* Returns the number of tuples (rows) affected by the SQL command.
|
614
633
|
*
|
615
|
-
* If the SQL command that generated the
|
634
|
+
* If the SQL command that generated the PG::Result was not one of:
|
616
635
|
* * +INSERT+
|
617
636
|
* * +UPDATE+
|
618
637
|
* * +DELETE+
|
@@ -706,19 +725,15 @@ pgresult_values(VALUE self)
|
|
706
725
|
int field;
|
707
726
|
int num_rows = PQntuples(result);
|
708
727
|
int num_fields = PQnfields(result);
|
709
|
-
VALUE
|
728
|
+
VALUE rows[ num_rows ];
|
710
729
|
|
711
730
|
for ( row = 0; row < num_rows; row++ ) {
|
712
|
-
|
713
|
-
VALUE new_row = rb_ary_new2(num_fields);
|
731
|
+
VALUE new_row[ num_fields ];
|
714
732
|
|
715
|
-
/*
|
716
|
-
rb_ary_store( ary, row, new_row );
|
717
|
-
|
718
|
-
/* populate it */
|
733
|
+
/* populate the row */
|
719
734
|
for ( field = 0; field < num_fields; field++ ) {
|
720
735
|
if ( PQgetisnull(result, row, field) ) {
|
721
|
-
|
736
|
+
new_row[ field ] = Qnil;
|
722
737
|
}
|
723
738
|
else {
|
724
739
|
VALUE val = rb_tainted_str_new( PQgetvalue(result, row, field),
|
@@ -732,16 +747,18 @@ pgresult_values(VALUE self)
|
|
732
747
|
rb_enc_associate( val, rb_ascii8bit_encoding() );
|
733
748
|
}
|
734
749
|
#endif
|
735
|
-
|
736
|
-
rb_ary_store( new_row, field, val );
|
750
|
+
new_row[ field ] = val;
|
737
751
|
}
|
738
752
|
}
|
753
|
+
|
754
|
+
rows[ row ] = rb_ary_new4( num_fields, new_row );
|
739
755
|
}
|
740
|
-
|
756
|
+
|
757
|
+
return rb_ary_new4( num_rows, rows );
|
741
758
|
}
|
742
759
|
|
743
760
|
|
744
|
-
/*
|
761
|
+
/*
|
745
762
|
* Make a Ruby array out of the encoded values from the specified
|
746
763
|
* column in the given result.
|
747
764
|
*/
|
@@ -749,16 +766,17 @@ static VALUE
|
|
749
766
|
make_column_result_array( VALUE self, int col )
|
750
767
|
{
|
751
768
|
PGresult *result = pgresult_get( self );
|
752
|
-
int
|
753
|
-
|
769
|
+
int rows = PQntuples( result );
|
770
|
+
int i;
|
754
771
|
VALUE val = Qnil;
|
772
|
+
VALUE results[ rows ];
|
755
773
|
|
756
774
|
if ( col >= PQnfields(result) )
|
757
775
|
rb_raise( rb_eIndexError, "no column %d in result", col );
|
758
776
|
|
759
|
-
|
760
|
-
val = rb_tainted_str_new( PQgetvalue(result,
|
761
|
-
PQgetlength(result,
|
777
|
+
for ( i=0; i < rows; i++ ) {
|
778
|
+
val = rb_tainted_str_new( PQgetvalue(result, i, col),
|
779
|
+
PQgetlength(result, i, col) );
|
762
780
|
|
763
781
|
#ifdef M17N_SUPPORTED
|
764
782
|
/* associate client encoding for text format only */
|
@@ -769,10 +787,10 @@ make_column_result_array( VALUE self, int col )
|
|
769
787
|
}
|
770
788
|
#endif
|
771
789
|
|
772
|
-
|
790
|
+
results[ i ] = val;
|
773
791
|
}
|
774
792
|
|
775
|
-
return
|
793
|
+
return rb_ary_new4( rows, results );
|
776
794
|
}
|
777
795
|
|
778
796
|
|
@@ -840,19 +858,18 @@ pgresult_each(VALUE self)
|
|
840
858
|
static VALUE
|
841
859
|
pgresult_fields(VALUE self)
|
842
860
|
{
|
843
|
-
PGresult *result;
|
844
|
-
|
845
|
-
|
861
|
+
PGresult *result = pgresult_get( self );
|
862
|
+
int n = PQnfields( result );
|
863
|
+
VALUE fields[ n ];
|
864
|
+
int i;
|
846
865
|
|
847
|
-
|
848
|
-
n = PQnfields(result);
|
849
|
-
ary = rb_ary_new2(n);
|
850
|
-
for (i=0;i<n;i++) {
|
866
|
+
for ( i = 0; i < n; i++ ) {
|
851
867
|
VALUE val = rb_tainted_str_new2(PQfname(result, i));
|
852
868
|
ASSOCIATE_INDEX(val, self);
|
853
|
-
|
869
|
+
fields[ i ] = val;
|
854
870
|
}
|
855
|
-
|
871
|
+
|
872
|
+
return rb_ary_new4( n, fields );
|
856
873
|
}
|
857
874
|
|
858
875
|
|
@@ -871,6 +888,8 @@ init_pg_result()
|
|
871
888
|
rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
|
872
889
|
rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
|
873
890
|
rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
|
891
|
+
rb_define_method(rb_cPGresult, "check", pg_result_check, 0);
|
892
|
+
rb_define_alias (rb_cPGresult, "check_result", "check");
|
874
893
|
rb_define_method(rb_cPGresult, "ntuples", pgresult_ntuples, 0);
|
875
894
|
rb_define_alias(rb_cPGresult, "num_tuples", "ntuples");
|
876
895
|
rb_define_method(rb_cPGresult, "nfields", pgresult_nfields, 0);
|
data/lib/1.8/pg_ext.so
CHANGED
Binary file
|
data/lib/1.9/pg_ext.so
CHANGED
Binary file
|
data/lib/pg.rb
CHANGED
data/lib/pg/connection.rb
CHANGED
@@ -51,6 +51,13 @@ class PG::Connection
|
|
51
51
|
return connopts.join(' ')
|
52
52
|
end
|
53
53
|
|
54
|
+
|
55
|
+
# Backward-compatibility aliases for stuff that's moved into PG.
|
56
|
+
class << self
|
57
|
+
define_method( :isthreadsafe, &PG.method(:isthreadsafe) )
|
58
|
+
end
|
59
|
+
|
60
|
+
|
54
61
|
end # class PG::Connection
|
55
62
|
|
56
63
|
# Backward-compatible alias
|
data/sample/async_api.rb
CHANGED
@@ -65,6 +65,8 @@ until poll_status == PG::PGRES_POLLING_OK ||
|
|
65
65
|
output_progress " negotiating SSL encryption."
|
66
66
|
when PG::CONNECTION_SETENV
|
67
67
|
output_progress " negotiating environment-driven parameter settings."
|
68
|
+
when PG::CONNECTION_NEEDED
|
69
|
+
output_progress " internal state: connect() needed."
|
68
70
|
end
|
69
71
|
|
70
72
|
# Check to see if it's finished or failed yet
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
# encoding: utf-8
|
4
|
+
|
5
|
+
require 'pg'
|
6
|
+
|
7
|
+
# This is a minimal example of a function that can test an existing PG::Connection and
|
8
|
+
# reset it if necessary.
|
9
|
+
|
10
|
+
def check_connection( conn )
|
11
|
+
begin
|
12
|
+
conn.exec( "SELECT 1" )
|
13
|
+
rescue PG::Error => err
|
14
|
+
$stderr.puts "%p while testing connection: %s" % [ err.class, err.message ]
|
15
|
+
conn.reset
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
conn = PG.connect( dbname: 'test' )
|
20
|
+
check_connection( conn )
|
21
|
+
|
@@ -0,0 +1,186 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# vim: set noet nosta sw=4 ts=4 :
|
3
|
+
#
|
4
|
+
# Quickly dump size information for a given database.
|
5
|
+
# Top twenty objects, and size per schema.
|
6
|
+
#
|
7
|
+
# Mahlon E. Smith <mahlon@martini.nu>
|
8
|
+
#
|
9
|
+
# Based on work by Jeff Davis <ruby@j-davis.com>.
|
10
|
+
#
|
11
|
+
|
12
|
+
|
13
|
+
begin
|
14
|
+
require 'ostruct'
|
15
|
+
require 'optparse'
|
16
|
+
require 'etc'
|
17
|
+
require 'pg'
|
18
|
+
|
19
|
+
rescue LoadError # 1.8 support
|
20
|
+
unless Object.const_defined?( :Gem )
|
21
|
+
require 'rubygems'
|
22
|
+
retry
|
23
|
+
end
|
24
|
+
raise
|
25
|
+
end
|
26
|
+
|
27
|
+
SCRIPT_VERSION = %q$Id$
|
28
|
+
|
29
|
+
|
30
|
+
### Gather data and output it to $stdout.
|
31
|
+
###
|
32
|
+
def report( opts )
|
33
|
+
db = PG.connect(
|
34
|
+
:dbname => opts.database,
|
35
|
+
:host => opts.host,
|
36
|
+
:port => opts.port,
|
37
|
+
:user => opts.user,
|
38
|
+
:password => opts.pass,
|
39
|
+
:sslmode => 'prefer'
|
40
|
+
)
|
41
|
+
|
42
|
+
# -----------------------------------------
|
43
|
+
|
44
|
+
db_info = db.exec %Q{
|
45
|
+
SELECT
|
46
|
+
count(oid) AS num_relations,
|
47
|
+
pg_size_pretty(pg_database_size('#{opts.database}')) AS dbsize
|
48
|
+
FROM
|
49
|
+
pg_class
|
50
|
+
}
|
51
|
+
|
52
|
+
puts '=' * 70
|
53
|
+
puts "Disk usage information for %s: (%d relations, %s total)" % [
|
54
|
+
opts.database,
|
55
|
+
db_info[0]['num_relations'],
|
56
|
+
db_info[0]['dbsize']
|
57
|
+
]
|
58
|
+
puts '=' * 70
|
59
|
+
|
60
|
+
# -----------------------------------------
|
61
|
+
|
62
|
+
top_twenty = db.exec %q{
|
63
|
+
SELECT
|
64
|
+
relname AS name,
|
65
|
+
relkind AS kind,
|
66
|
+
pg_size_pretty(pg_relation_size(pg_class.oid)) AS size
|
67
|
+
FROM
|
68
|
+
pg_class
|
69
|
+
ORDER BY
|
70
|
+
pg_relation_size(pg_class.oid) DESC
|
71
|
+
LIMIT 20
|
72
|
+
}
|
73
|
+
|
74
|
+
puts 'Top twenty objects by size:'
|
75
|
+
puts '-' * 70
|
76
|
+
top_twenty.each do |row|
|
77
|
+
type = case row['kind']
|
78
|
+
when 'i'; 'index'
|
79
|
+
when 't'; 'toast'
|
80
|
+
when 'r'; 'table'
|
81
|
+
when 'S'; 'sequence'
|
82
|
+
else; '???'
|
83
|
+
end
|
84
|
+
|
85
|
+
puts "%40s %10s (%s)" % [ row['name'], row['size'], type ]
|
86
|
+
end
|
87
|
+
puts '-' * 70
|
88
|
+
|
89
|
+
# -----------------------------------------
|
90
|
+
|
91
|
+
schema_sizes = db.exec %q{
|
92
|
+
SELECT
|
93
|
+
table_schema,
|
94
|
+
pg_size_pretty( CAST( SUM(pg_total_relation_size(table_schema || '.' || table_name)) AS bigint)) AS size
|
95
|
+
FROM
|
96
|
+
information_schema.tables
|
97
|
+
GROUP BY
|
98
|
+
table_schema
|
99
|
+
ORDER BY
|
100
|
+
CAST( SUM(pg_total_relation_size(table_schema || '.' || table_name)) AS bigint ) DESC
|
101
|
+
}
|
102
|
+
|
103
|
+
|
104
|
+
puts 'Size per schema:'
|
105
|
+
puts '-' * 70
|
106
|
+
schema_sizes.each do |row|
|
107
|
+
puts "%20s %10s" % [ row['table_schema'], row['size'] ]
|
108
|
+
end
|
109
|
+
puts '-' * 70
|
110
|
+
puts
|
111
|
+
|
112
|
+
db.finish
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
### Parse command line arguments. Return a struct of global options.
|
117
|
+
###
|
118
|
+
def parse_args( args )
|
119
|
+
options = OpenStruct.new
|
120
|
+
options.database = Etc.getpwuid( Process.uid ).name
|
121
|
+
options.host = '127.0.0.1'
|
122
|
+
options.port = 5432
|
123
|
+
options.user = Etc.getpwuid( Process.uid ).name
|
124
|
+
options.sslmode = 'prefer'
|
125
|
+
options.interval = 5
|
126
|
+
|
127
|
+
opts = OptionParser.new do |opts|
|
128
|
+
opts.banner = "Usage: #{$0} [options]"
|
129
|
+
|
130
|
+
opts.separator ''
|
131
|
+
opts.separator 'Connection options:'
|
132
|
+
|
133
|
+
opts.on( '-d', '--database DBNAME',
|
134
|
+
"specify the database to connect to (default: \"#{options.database}\")" ) do |db|
|
135
|
+
options.database = db
|
136
|
+
end
|
137
|
+
|
138
|
+
opts.on( '-h', '--host HOSTNAME', 'database server host' ) do |host|
|
139
|
+
options.host = host
|
140
|
+
end
|
141
|
+
|
142
|
+
opts.on( '-p', '--port PORT', Integer,
|
143
|
+
"database server port (default: \"#{options.port}\")" ) do |port|
|
144
|
+
options.port = port
|
145
|
+
end
|
146
|
+
|
147
|
+
opts.on( '-U', '--user NAME',
|
148
|
+
"database user name (default: \"#{options.user}\")" ) do |user|
|
149
|
+
options.user = user
|
150
|
+
end
|
151
|
+
|
152
|
+
opts.on( '-W', 'force password prompt' ) do |pw|
|
153
|
+
print 'Password: '
|
154
|
+
begin
|
155
|
+
system 'stty -echo'
|
156
|
+
options.pass = gets.chomp
|
157
|
+
ensure
|
158
|
+
system 'stty echo'
|
159
|
+
puts
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
opts.separator ''
|
164
|
+
opts.separator 'Other options:'
|
165
|
+
|
166
|
+
opts.on_tail( '--help', 'show this help, then exit' ) do
|
167
|
+
$stderr.puts opts
|
168
|
+
exit
|
169
|
+
end
|
170
|
+
|
171
|
+
opts.on_tail( '--version', 'output version information, then exit' ) do
|
172
|
+
puts SCRIPT_VERSION
|
173
|
+
exit
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
opts.parse!( args )
|
178
|
+
return options
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
if __FILE__ == $0
|
183
|
+
opts = parse_args( ARGV )
|
184
|
+
report( opts )
|
185
|
+
end
|
186
|
+
|