methadone 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE.txt +201 -0
- data/README.rdoc +0 -4
- data/Rakefile +2 -1
- data/bin/methadone +10 -4
- data/features/bootstrap.feature +5 -1
- data/features/license.feature +27 -0
- data/features/readme.feature +26 -0
- data/features/step_definitions/bootstrap_steps.rb +1 -0
- data/features/step_definitions/readme_steps.rb +26 -0
- data/lib/methadone/main.rb +23 -7
- data/lib/methadone/version.rb +1 -1
- data/methadone.gemspec +1 -0
- data/templates/full/.gitignore.erb +4 -0
- data/templates/full/README.rdoc.erb +19 -0
- data/templates/full/Rakefile.erb +3 -0
- data/test/base_test.rb +6 -1
- data/test/test_cli_logger.rb +117 -81
- data/test/test_cli_logging.rb +49 -26
- data/test/test_main.rb +261 -170
- metadata +32 -12
data/lib/methadone/version.rb
CHANGED
data/methadone.gemspec
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
= <%= gemname %> - DESCRIBE YOUR GEM
|
2
|
+
|
3
|
+
Author:: YOUR NAME (YOUR EMAIL)
|
4
|
+
Copyright:: Copyright (c) <%= Time.now.year %> YOUR NAME
|
5
|
+
License::
|
6
|
+
|
7
|
+
DESCRIBE YOUR GEM HERE
|
8
|
+
|
9
|
+
== Links
|
10
|
+
|
11
|
+
* {Source on Github}[LINK TO GITHUB]
|
12
|
+
* RDoc[LINK TO RDOC.INFO]
|
13
|
+
|
14
|
+
== Install
|
15
|
+
|
16
|
+
== Examples
|
17
|
+
|
18
|
+
== Contributing
|
19
|
+
|
data/templates/full/Rakefile.erb
CHANGED
@@ -3,6 +3,7 @@ require 'rake/clean'
|
|
3
3
|
require 'rake/testtask'
|
4
4
|
require 'cucumber'
|
5
5
|
require 'cucumber/rake/task'
|
6
|
+
gem 'rdoc' # we need the installed RDoc gem, not the system one
|
6
7
|
require 'rdoc/task'
|
7
8
|
|
8
9
|
include Rake::DSL
|
@@ -21,7 +22,9 @@ Cucumber::Rake::Task.new(:features) do |t|
|
|
21
22
|
end
|
22
23
|
|
23
24
|
Rake::RDocTask.new do |rd|
|
25
|
+
<% if using_readme %>
|
24
26
|
rd.main = "README.rdoc"
|
27
|
+
<% end %>
|
25
28
|
rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
|
26
29
|
end
|
27
30
|
|
data/test/base_test.rb
CHANGED
@@ -4,8 +4,9 @@ SimpleCov.start do
|
|
4
4
|
end
|
5
5
|
require 'test/unit'
|
6
6
|
require 'rspec/expectations'
|
7
|
+
require 'test/unit/given'
|
7
8
|
|
8
|
-
class BaseTest < Test::Unit::TestCase
|
9
|
+
class BaseTest < Test::Unit::Given::TestCase
|
9
10
|
# Copied from Rails; makes a test method using a string
|
10
11
|
def self.test(name, &block)
|
11
12
|
test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
|
@@ -19,4 +20,8 @@ class BaseTest < Test::Unit::TestCase
|
|
19
20
|
end
|
20
21
|
end
|
21
22
|
end
|
23
|
+
|
24
|
+
def test_nothing
|
25
|
+
# Seems 1.8 wants to have a test here?
|
26
|
+
end
|
22
27
|
end
|
data/test/test_cli_logger.rb
CHANGED
@@ -20,116 +20,136 @@ class TestCLILogger < BaseTest
|
|
20
20
|
$stdout = @real_stdout
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
23
|
+
test_that "when both stderr and stdin are ttys, split the log messages between them and don't format" do
|
24
|
+
Given {
|
25
|
+
class << $stderr
|
26
|
+
def tty?; true; end
|
27
|
+
end
|
28
|
+
class << $stdout
|
29
|
+
def tty?; true; end
|
30
|
+
end
|
31
|
+
|
32
|
+
@logger = CLILogger.new
|
33
|
+
@logger.level = Logger::DEBUG
|
34
|
+
}
|
33
35
|
|
34
|
-
|
35
|
-
logger.info("info")
|
36
|
-
logger.warn("warn")
|
37
|
-
logger.error("error")
|
38
|
-
logger.fatal("fatal")
|
36
|
+
When log_all_levels
|
39
37
|
|
40
|
-
|
41
|
-
|
38
|
+
Then {
|
39
|
+
$stdout.string.should == "debug\ninfo\n"
|
40
|
+
$stderr.string.should == "warn\nerror\nfatal\n"
|
41
|
+
}
|
42
42
|
end
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
logger.debug("debug")
|
48
|
-
logger.info("info")
|
49
|
-
logger.warn("warn")
|
50
|
-
logger.error("error")
|
51
|
-
logger.fatal("fatal")
|
44
|
+
test_that "logger sends debug and info to stdout, and warns, errors, and fatals to stderr" do
|
45
|
+
Given a_logger_with_blank_format
|
46
|
+
When log_all_levels
|
52
47
|
|
53
|
-
|
54
|
-
|
48
|
+
Then stdout_should_have_everything
|
49
|
+
And {
|
50
|
+
$stderr.string.should == "warn\nerror\nfatal\n"
|
51
|
+
}
|
55
52
|
end
|
56
53
|
|
57
|
-
|
58
|
-
|
59
|
-
logger.error_level = Logger::Severity::FATAL
|
54
|
+
test_that "we can control what goes to stderr" do
|
55
|
+
Given a_logger_with_blank_format :at_error_level => Logger::Severity::FATAL
|
60
56
|
|
61
|
-
|
62
|
-
logger.info("info")
|
63
|
-
logger.warn("warn")
|
64
|
-
logger.error("error")
|
65
|
-
logger.fatal("fatal")
|
57
|
+
When log_all_levels
|
66
58
|
|
67
|
-
|
68
|
-
|
59
|
+
Then stdout_should_have_everything
|
60
|
+
And {
|
61
|
+
$stderr.string.should == "fatal\n"
|
62
|
+
}
|
69
63
|
end
|
70
64
|
|
71
|
-
|
72
|
-
|
73
|
-
|
65
|
+
test_that "we can log to alternate devices easily" do
|
66
|
+
Given {
|
67
|
+
@out = StringIO.new
|
68
|
+
@err = StringIO.new
|
74
69
|
|
75
|
-
|
76
|
-
|
77
|
-
|
70
|
+
@logger = CLILogger.new(@out,@err)
|
71
|
+
@logger.level = Logger::DEBUG
|
72
|
+
@logger.formatter = @blank_format
|
73
|
+
}
|
78
74
|
|
79
|
-
|
80
|
-
logger.info("info")
|
81
|
-
logger.warn("warn")
|
82
|
-
logger.error("error")
|
83
|
-
logger.fatal("fatal")
|
75
|
+
When log_all_levels
|
84
76
|
|
85
|
-
|
86
|
-
|
77
|
+
Then {
|
78
|
+
@out.string.should == "debug\ninfo\nwarn\nerror\nfatal\n"
|
79
|
+
@err.string.should == "warn\nerror\nfatal\n"
|
80
|
+
}
|
87
81
|
end
|
88
82
|
|
89
83
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
logger.debug("debug")
|
94
|
-
logger.info("info")
|
95
|
-
logger.warn("warn")
|
96
|
-
logger.error("error")
|
97
|
-
logger.fatal("fatal")
|
84
|
+
test_that "error logger ignores the log level" do
|
85
|
+
Given a_logger_with_blank_format :at_level => Logger::Severity::FATAL
|
86
|
+
When log_all_levels
|
98
87
|
|
99
|
-
|
100
|
-
|
88
|
+
Then {
|
89
|
+
$stdout.string.should == "fatal\n"
|
90
|
+
$stderr.string.should == "warn\nerror\nfatal\n"
|
91
|
+
}
|
101
92
|
end
|
102
93
|
|
103
|
-
|
104
|
-
|
105
|
-
logger
|
106
|
-
logger.
|
107
|
-
logger.
|
108
|
-
|
109
|
-
|
110
|
-
|
94
|
+
test_that "both loggers use the same date format" do
|
95
|
+
Given {
|
96
|
+
@logger = CLILogger.new
|
97
|
+
@logger.level = Logger::DEBUG
|
98
|
+
@logger.datetime_format = "the time"
|
99
|
+
}
|
100
|
+
|
101
|
+
When {
|
102
|
+
@logger.debug("debug")
|
103
|
+
@logger.error("error")
|
104
|
+
}
|
105
|
+
|
106
|
+
Then {
|
107
|
+
$stdout.string.should match /the time.*DEBUG.*debug/
|
108
|
+
$stderr.string.should match /the time.*ERROR.*error/
|
109
|
+
}
|
111
110
|
end
|
112
111
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
112
|
+
test_that "error logger does not get <<" do
|
113
|
+
Given a_logger_with_blank_format
|
114
|
+
When {
|
115
|
+
@logger << "foo"
|
116
|
+
}
|
117
|
+
Then {
|
118
|
+
$stdout.string.should == "foo"
|
119
|
+
$stderr.string.should == ""
|
120
|
+
}
|
118
121
|
end
|
119
122
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
123
|
+
test_that "error logger can have a different format" do
|
124
|
+
Given {
|
125
|
+
@logger = logger_with_blank_format
|
126
|
+
@logger.error_formatter = proc do |severity,datetime,progname,msg|
|
127
|
+
"ERROR_LOGGER: #{msg}\n"
|
128
|
+
end
|
129
|
+
}
|
130
|
+
When {
|
131
|
+
@logger.debug("debug")
|
132
|
+
@logger.error("error")
|
133
|
+
}
|
134
|
+
Then {
|
135
|
+
$stdout.string.should == "debug\nerror\n"
|
136
|
+
$stderr.string.should == "ERROR_LOGGER: error\n"
|
124
137
|
}
|
125
|
-
logger.debug("debug")
|
126
|
-
logger.error("error")
|
127
|
-
$stdout.string.should == "debug\nerror\n"
|
128
|
-
$stderr.string.should == "ERROR_LOGGER: error\n"
|
129
138
|
end
|
130
139
|
|
131
140
|
private
|
132
141
|
|
142
|
+
def log_all_levels
|
143
|
+
proc do
|
144
|
+
@logger.debug("debug")
|
145
|
+
@logger.info("info")
|
146
|
+
@logger.warn("warn")
|
147
|
+
@logger.error("error")
|
148
|
+
@logger.fatal("fatal")
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
|
133
153
|
def logger_with_blank_format
|
134
154
|
logger = CLILogger.new
|
135
155
|
logger.formatter = @blank_format
|
@@ -137,4 +157,20 @@ class TestCLILogger < BaseTest
|
|
137
157
|
logger
|
138
158
|
end
|
139
159
|
|
160
|
+
# options - :at_level - level to set the logger
|
161
|
+
def a_logger_with_blank_format(options = {})
|
162
|
+
proc do
|
163
|
+
@logger = logger_with_blank_format
|
164
|
+
@logger.level = options[:at_level] if options[:at_level]
|
165
|
+
@logger.error_level = options[:at_error_level] if options[:at_error_level]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def stdout_should_have_everything
|
170
|
+
proc do
|
171
|
+
$stdout.string.should == "debug\ninfo\nwarn\nerror\nfatal\n"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
|
140
176
|
end
|
data/test/test_cli_logging.rb
CHANGED
@@ -20,6 +20,55 @@ class TestCLILogging < BaseTest
|
|
20
20
|
$stdout = @real_stdout
|
21
21
|
end
|
22
22
|
|
23
|
+
test_that "a class can include CLILogging and get terser logging" do
|
24
|
+
Given {
|
25
|
+
@class_with_logger = MyClassThatLogsToStdout.new
|
26
|
+
}
|
27
|
+
|
28
|
+
When {
|
29
|
+
@class_with_logger.doit
|
30
|
+
}
|
31
|
+
|
32
|
+
Then {
|
33
|
+
$stdout.string.should == "debug\ninfo\nwarn\nerror\nfatal\n"
|
34
|
+
$stderr.string.should == "warn\nerror\nfatal\n"
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
test_that "another class using CLILogging gets the same logger instance" do
|
39
|
+
Given {
|
40
|
+
@first = MyClassThatLogsToStdout.new
|
41
|
+
@second = MyOtherClassThatLogsToStdout.new
|
42
|
+
}
|
43
|
+
Then {
|
44
|
+
@first.logger_id.should == @second.logger_id
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
test_that "we can change the global logger" do
|
49
|
+
Given {
|
50
|
+
@first = MyClassThatLogsToStdout.new
|
51
|
+
@second = MyOtherClassThatLogsToStdout.new
|
52
|
+
@logger_id = @second.logger_id
|
53
|
+
}
|
54
|
+
When {
|
55
|
+
@second.change_logger
|
56
|
+
}
|
57
|
+
Then {
|
58
|
+
@logger_id.should_not == @second.logger_id
|
59
|
+
@first.logger_id.should == @second.logger_id
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
test_that "we cannot use a nil logger" do
|
64
|
+
Given {
|
65
|
+
@other_class = MyOtherClassThatLogsToStdout.new
|
66
|
+
}
|
67
|
+
Then {
|
68
|
+
lambda { MyOtherClassThatLogsToStdout.new.change_to_nil_logger }.should raise_error(ArgumentError)
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
23
72
|
class MyClassThatLogsToStdout
|
24
73
|
include Methadone::CLILogging
|
25
74
|
|
@@ -41,32 +90,6 @@ class TestCLILogging < BaseTest
|
|
41
90
|
def logger_id; logger.object_id; end
|
42
91
|
end
|
43
92
|
|
44
|
-
test "a class can include CLILogging and get terser logging" do
|
45
|
-
MyClassThatLogsToStdout.new.doit
|
46
|
-
$stdout.string.should == "debug\ninfo\nwarn\nerror\nfatal\n"
|
47
|
-
$stderr.string.should == "warn\nerror\nfatal\n"
|
48
|
-
end
|
49
|
-
|
50
|
-
test "another class using CLILogging gets the same logger instance" do
|
51
|
-
first = MyClassThatLogsToStdout.new
|
52
|
-
second = MyOtherClassThatLogsToStdout.new
|
53
|
-
first.logger_id.should == second.logger_id
|
54
|
-
end
|
55
|
-
|
56
|
-
test "we can change the global logger" do
|
57
|
-
first = MyClassThatLogsToStdout.new
|
58
|
-
second = MyOtherClassThatLogsToStdout.new
|
59
|
-
logger_id = second.logger_id
|
60
|
-
|
61
|
-
second.change_logger
|
62
|
-
|
63
|
-
logger_id.should_not == second.logger_id
|
64
|
-
first.logger_id.should == second.logger_id
|
65
|
-
end
|
66
|
-
|
67
|
-
test "we cannot use a nil logger" do
|
68
|
-
lambda { MyOtherClassThatLogsToStdout.new.change_to_nil_logger }.should raise_error(ArgumentError)
|
69
|
-
end
|
70
93
|
|
71
94
|
class MyOtherClassThatLogsToStdout
|
72
95
|
include Methadone::CLILogging
|
data/test/test_main.rb
CHANGED
@@ -20,245 +20,336 @@ class TestMain < BaseTest
|
|
20
20
|
set_argv @original_argv
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
23
|
+
test_that "my main block gets called by run and has access to CLILogging" do
|
24
|
+
Given {
|
25
|
+
@called = false
|
26
|
+
main do
|
27
|
+
begin
|
28
|
+
debug "debug"
|
29
|
+
info "info"
|
30
|
+
warn "warn"
|
31
|
+
error "error"
|
32
|
+
fatal "fatal"
|
33
|
+
@called = true
|
34
|
+
rescue => ex
|
35
|
+
puts ex.message
|
36
|
+
end
|
35
37
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
38
|
+
}
|
39
|
+
When run_go_safely
|
40
|
+
Then main_shouldve_been_called
|
39
41
|
end
|
40
42
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
43
|
+
test_that "my main block gets the command-line parameters" do
|
44
|
+
Given {
|
45
|
+
@params = []
|
46
|
+
main do |param1,param2,param3|
|
47
|
+
@params << param1
|
48
|
+
@params << param2
|
49
|
+
@params << param3
|
50
|
+
end
|
51
|
+
set_argv %w(one two three)
|
52
|
+
}
|
53
|
+
When run_go_safely
|
54
|
+
Then {
|
55
|
+
@params.should == %w(one two three)
|
56
|
+
}
|
51
57
|
end
|
52
58
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
59
|
+
test_that "my main block can freely ignore arguments given" do
|
60
|
+
Given {
|
61
|
+
@called = false
|
62
|
+
main do
|
63
|
+
@called = true
|
64
|
+
end
|
65
|
+
set_argv %w(one two three)
|
66
|
+
}
|
67
|
+
When run_go_safely
|
68
|
+
Then main_shouldve_been_called
|
61
69
|
end
|
62
70
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
71
|
+
test_that "my main block can ask for arguments that it might not receive" do
|
72
|
+
Given {
|
73
|
+
@params = []
|
74
|
+
main do |param1,param2,param3|
|
75
|
+
@params << param1
|
76
|
+
@params << param2
|
77
|
+
@params << param3
|
78
|
+
end
|
79
|
+
set_argv %w(one two)
|
80
|
+
}
|
81
|
+
When run_go_safely
|
82
|
+
Then {
|
83
|
+
@params.should == ['one','two',nil]
|
84
|
+
}
|
73
85
|
end
|
74
86
|
|
75
|
-
|
87
|
+
test_that "go exits zero when main evaluates to nil or some other non number" do
|
76
88
|
[nil,'some string',Object.new,[],4.5].each do |non_number|
|
77
|
-
|
78
|
-
|
89
|
+
Given main_that_exits non_number
|
90
|
+
Then {
|
91
|
+
assert_exits(0,"for value #{non_number}") { When run_go! }
|
92
|
+
}
|
79
93
|
end
|
80
94
|
end
|
81
95
|
|
82
|
-
|
96
|
+
def run_go!; proc { go! }; end
|
97
|
+
|
98
|
+
test_that "go exits with the numeric value that main evaluated to" do
|
83
99
|
[0,1,2,3].each do |exit_status|
|
84
|
-
|
85
|
-
|
100
|
+
Given main_that_exits exit_status
|
101
|
+
Then {
|
102
|
+
assert_exits(exit_status) { When run_go! }
|
103
|
+
}
|
86
104
|
end
|
87
105
|
end
|
88
106
|
|
89
|
-
|
90
|
-
main
|
91
|
-
raise "oh noes"
|
92
|
-
end
|
93
|
-
assert_exits(70) { go! }
|
94
|
-
assert_logged_at_error "oh noes"
|
107
|
+
def main_that_exits(exit_status)
|
108
|
+
proc { main { exit_status } }
|
95
109
|
end
|
96
110
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
111
|
+
test_that "go exits with 70, which is the Linux sysexits.h code for this sort of thing, if there's an exception" do
|
112
|
+
Given {
|
113
|
+
main do
|
114
|
+
raise "oh noes"
|
115
|
+
end
|
116
|
+
}
|
117
|
+
Then {
|
118
|
+
assert_exits(70) { When run_go! }
|
119
|
+
assert_logged_at_error "oh noes"
|
120
|
+
}
|
103
121
|
end
|
104
122
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
123
|
+
test_that "go exits with the exit status included in the special-purpose excepiton" do
|
124
|
+
Given {
|
125
|
+
main do
|
126
|
+
raise Methadone::Error.new(4,"oh noes")
|
127
|
+
end
|
128
|
+
}
|
129
|
+
Then {
|
130
|
+
assert_exits(4) { When run_go! }
|
131
|
+
assert_logged_at_error "oh noes"
|
132
|
+
}
|
111
133
|
end
|
112
134
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
135
|
+
test_that "can exit with a specific status by using the helper method instead of making a new exception" do
|
136
|
+
Given {
|
137
|
+
main do
|
138
|
+
exit_now!(4,"oh noes")
|
139
|
+
end
|
140
|
+
}
|
141
|
+
Then {
|
142
|
+
assert_exits(4) { When run_go! }
|
143
|
+
assert_logged_at_error "oh noes"
|
144
|
+
}
|
145
|
+
end
|
120
146
|
|
121
|
-
|
122
|
-
|
147
|
+
test_that "opts allows us to more expediently set up OptionParser" do
|
148
|
+
Given {
|
149
|
+
@switch = nil
|
150
|
+
@flag = nil
|
151
|
+
main do
|
152
|
+
@switch = options[:switch]
|
153
|
+
@flag = options[:flag]
|
154
|
+
end
|
155
|
+
|
156
|
+
opts.on("--switch") { options[:switch] = true }
|
157
|
+
opts.on("--flag FLAG") { |value| options[:flag] = value }
|
123
158
|
|
124
|
-
|
159
|
+
set_argv %w(--switch --flag value)
|
160
|
+
}
|
125
161
|
|
126
|
-
|
162
|
+
When run_go_safely
|
127
163
|
|
128
|
-
|
129
|
-
|
164
|
+
Then {
|
165
|
+
@switch.should be true
|
166
|
+
@flag.should == 'value'
|
167
|
+
}
|
130
168
|
end
|
131
169
|
|
132
|
-
|
133
|
-
|
134
|
-
|
170
|
+
test_that "when the command line is invalid, we exit with 64" do
|
171
|
+
Given {
|
172
|
+
main do
|
173
|
+
end
|
135
174
|
|
136
|
-
|
137
|
-
|
175
|
+
opts.on("--switch") { options[:switch] = true }
|
176
|
+
opts.on("--flag FLAG") { |value| options[:flag] = value }
|
138
177
|
|
139
|
-
|
178
|
+
set_argv %w(--invalid --flag value)
|
179
|
+
}
|
140
180
|
|
141
|
-
|
181
|
+
Then {
|
182
|
+
assert_exits(64) { When run_go! }
|
183
|
+
}
|
142
184
|
end
|
143
185
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
186
|
+
test_that "omitting the block to opts simply sets the value in the options hash and returns itself" do
|
187
|
+
Given {
|
188
|
+
@switch = nil
|
189
|
+
@negatable = nil
|
190
|
+
@flag = nil
|
191
|
+
@f = nil
|
192
|
+
@other = nil
|
193
|
+
@some_other = nil
|
194
|
+
main do
|
195
|
+
@switch = options[:switch]
|
196
|
+
@flag = options[:flag]
|
197
|
+
@f = options[:f]
|
198
|
+
@negatable = options[:negatable]
|
199
|
+
@other = options[:other]
|
200
|
+
@some_other = options[:some_other]
|
201
|
+
end
|
159
202
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
203
|
+
on("--switch")
|
204
|
+
on("--[no-]negatable")
|
205
|
+
on("--flag FLAG","-f","Some documentation string")
|
206
|
+
on("--other") do
|
207
|
+
options[:some_other] = true
|
208
|
+
end
|
166
209
|
|
167
|
-
|
210
|
+
set_argv %w(--switch --flag value --negatable --other)
|
211
|
+
}
|
168
212
|
|
169
|
-
|
213
|
+
When run_go_safely
|
170
214
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
215
|
+
Then {
|
216
|
+
@switch.should be true
|
217
|
+
@some_other.should be true
|
218
|
+
@other.should_not be true
|
219
|
+
@flag.should == 'value'
|
220
|
+
@f.should == 'value'
|
221
|
+
opts.to_s.should match /Some documentation string/
|
222
|
+
}
|
177
223
|
end
|
178
224
|
|
179
|
-
|
180
|
-
|
225
|
+
test_that "without specifying options, [options] doesn't show up in our banner" do
|
226
|
+
Given {
|
227
|
+
main {}
|
228
|
+
}
|
181
229
|
|
182
|
-
|
230
|
+
Then {
|
231
|
+
opts.banner.should_not match /\[options\]/
|
232
|
+
}
|
183
233
|
end
|
184
234
|
|
185
|
-
|
186
|
-
|
187
|
-
|
235
|
+
test_that "when specifying an option, [options] shows up in the banner" do
|
236
|
+
Given {
|
237
|
+
main {}
|
238
|
+
on("-s")
|
239
|
+
}
|
240
|
+
|
241
|
+
Then {
|
242
|
+
opts.banner.should match /\[options\]/
|
243
|
+
}
|
188
244
|
|
189
|
-
assert_match /\[options\]/,opts.banner
|
190
245
|
end
|
191
246
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
247
|
+
test_that "I can specify which arguments my app takes and if they are required" do
|
248
|
+
Given {
|
249
|
+
main {}
|
250
|
+
|
251
|
+
arg :db_name
|
252
|
+
arg :user, :required
|
253
|
+
arg :password, :optional
|
254
|
+
}
|
198
255
|
|
199
|
-
|
256
|
+
Then {
|
257
|
+
opts.banner.should match /db_name user \[password\]$/
|
258
|
+
}
|
200
259
|
end
|
201
260
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
arg :db_name
|
206
|
-
arg :user, :required, :one
|
207
|
-
arg :tables, :many
|
261
|
+
test_that "I can specify which arguments my app takes and if they are singular or plural" do
|
262
|
+
Given {
|
263
|
+
main {}
|
208
264
|
|
209
|
-
|
210
|
-
|
265
|
+
arg :db_name
|
266
|
+
arg :user, :required, :one
|
267
|
+
arg :tables, :many
|
268
|
+
}
|
211
269
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
arg :user, :required, :one
|
217
|
-
arg :tables, :any
|
270
|
+
Then {
|
271
|
+
opts.banner.should match /db_name user tables...$/
|
272
|
+
}
|
273
|
+
end
|
218
274
|
|
219
|
-
|
275
|
+
test_that "I can specify which arguments my app takes and if they are singular or optional plural" do
|
276
|
+
Given {
|
277
|
+
main {}
|
278
|
+
|
279
|
+
arg :db_name
|
280
|
+
arg :user, :required, :one
|
281
|
+
arg :tables, :any
|
282
|
+
}
|
283
|
+
|
284
|
+
Then {
|
285
|
+
opts.banner.should match /db_name user \[tables...\]$/
|
286
|
+
}
|
220
287
|
end
|
221
288
|
|
222
|
-
|
223
|
-
|
224
|
-
|
289
|
+
test_that "I can set a description for my app" do
|
290
|
+
Given {
|
291
|
+
main {}
|
292
|
+
description "An app of total awesome"
|
225
293
|
|
226
|
-
|
294
|
+
}
|
295
|
+
Then {
|
296
|
+
opts.banner.should match /^An app of total awesome$/
|
297
|
+
}
|
227
298
|
end
|
228
299
|
|
229
|
-
|
230
|
-
|
231
|
-
|
300
|
+
test_that "when I override the banner, we don't automatically do anything" do
|
301
|
+
Given {
|
302
|
+
main {}
|
303
|
+
opts.banner = "FOOBAR"
|
232
304
|
|
233
|
-
|
305
|
+
on("-s")
|
306
|
+
}
|
234
307
|
|
235
|
-
|
308
|
+
Then {
|
309
|
+
opts.banner.should == 'FOOBAR'
|
310
|
+
}
|
236
311
|
end
|
237
312
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
313
|
+
test_that "when I say an argument is required and its omitted, I get an error" do
|
314
|
+
Given {
|
315
|
+
main {}
|
316
|
+
arg :foo
|
317
|
+
arg :bar
|
242
318
|
|
243
|
-
|
319
|
+
set_argv %w(blah)
|
320
|
+
}
|
244
321
|
|
245
|
-
|
246
|
-
|
322
|
+
Then {
|
323
|
+
assert_exits(64) { When run_go! }
|
324
|
+
assert_logged_at_error("parse error: 'bar' is required")
|
325
|
+
}
|
247
326
|
end
|
248
327
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
328
|
+
test_that "when I say an argument is many and its omitted, I get an error" do
|
329
|
+
Given {
|
330
|
+
main {}
|
331
|
+
arg :foo
|
332
|
+
arg :bar, :many
|
253
333
|
|
254
|
-
|
334
|
+
set_argv %w(blah)
|
335
|
+
}
|
255
336
|
|
256
|
-
|
257
|
-
|
337
|
+
Then {
|
338
|
+
assert_exits(64) { When run_go! }
|
339
|
+
assert_logged_at_error("parse error: at least one 'bar' is required")
|
340
|
+
}
|
258
341
|
end
|
259
342
|
|
260
343
|
private
|
261
344
|
|
345
|
+
def main_shouldve_been_called
|
346
|
+
Proc.new { assert @called,"Main block wasn't called?!" }
|
347
|
+
end
|
348
|
+
|
349
|
+
def run_go_safely
|
350
|
+
Proc.new { safe_go! }
|
351
|
+
end
|
352
|
+
|
262
353
|
# Calls go!, but traps the exit
|
263
354
|
def safe_go!
|
264
355
|
go!
|
@@ -266,14 +357,14 @@ class TestMain < BaseTest
|
|
266
357
|
end
|
267
358
|
|
268
359
|
def assert_logged_at_error(expected_message)
|
269
|
-
|
360
|
+
@logged.should include expected_message
|
270
361
|
end
|
271
362
|
|
272
363
|
def assert_exits(exit_code,message='',&block)
|
273
364
|
block.call
|
274
365
|
fail "Expected an exit of #{exit_code}, but we didn't even exit!"
|
275
366
|
rescue SystemExit => ex
|
276
|
-
|
367
|
+
ex.status.should == exit_code
|
277
368
|
end
|
278
369
|
|
279
370
|
def set_argv(args)
|