gli 1.6.0 → 2.0.0.rc3
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/.gitignore +11 -0
- data/.rvmrc +1 -0
- data/.travis.yml +10 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +201 -0
- data/ObjectModel.graffle +1191 -0
- data/README.rdoc +60 -10
- data/Rakefile +145 -0
- data/bin/gli +12 -30
- data/bin/report_on_rake_results +10 -0
- data/bin/test_all_rubies.sh +6 -0
- data/features/gli_executable.feature +84 -0
- data/features/gli_init.feature +219 -0
- data/features/step_definitions/gli_executable_steps.rb +12 -0
- data/features/step_definitions/gli_init_steps.rb +11 -0
- data/features/step_definitions/todo_steps.rb +69 -0
- data/features/support/env.rb +49 -0
- data/features/todo.feature +182 -0
- data/gli.cheat +95 -0
- data/gli.gemspec +34 -0
- data/lib/gli.rb +11 -571
- data/lib/gli/app.rb +184 -0
- data/lib/gli/app_support.rb +226 -0
- data/lib/gli/command.rb +107 -95
- data/lib/gli/command_line_option.rb +34 -0
- data/lib/gli/command_line_token.rb +13 -9
- data/lib/gli/command_support.rb +200 -0
- data/lib/gli/commands/compound_command.rb +42 -0
- data/lib/gli/commands/help.rb +63 -0
- data/lib/gli/commands/help_modules/command_help_format.rb +134 -0
- data/lib/gli/commands/help_modules/global_help_format.rb +61 -0
- data/lib/gli/commands/help_modules/list_formatter.rb +22 -0
- data/lib/gli/commands/help_modules/options_formatter.rb +50 -0
- data/lib/gli/commands/help_modules/text_wrapper.rb +53 -0
- data/lib/gli/commands/initconfig.rb +67 -0
- data/lib/{support → gli/commands}/scaffold.rb +150 -34
- data/lib/gli/dsl.rb +194 -0
- data/lib/gli/exceptions.rb +13 -4
- data/lib/gli/flag.rb +30 -41
- data/lib/gli/gli_option_parser.rb +98 -0
- data/lib/gli/option_parser_factory.rb +44 -0
- data/lib/gli/options.rb +2 -1
- data/lib/gli/switch.rb +19 -51
- data/lib/gli/terminal.rb +30 -20
- data/lib/gli/version.rb +5 -0
- data/test/apps/README.md +2 -0
- data/test/apps/todo/Gemfile +2 -0
- data/test/apps/todo/README.rdoc +6 -0
- data/test/apps/todo/Rakefile +23 -0
- data/test/apps/todo/bin/todo +52 -0
- data/test/apps/todo/lib/todo/commands/create.rb +22 -0
- data/test/apps/todo/lib/todo/commands/list.rb +53 -0
- data/test/apps/todo/lib/todo/commands/ls.rb +47 -0
- data/test/apps/todo/lib/todo/version.rb +3 -0
- data/test/apps/todo/test/tc_nothing.rb +14 -0
- data/test/apps/todo/todo.gemspec +23 -0
- data/test/apps/todo/todo.rdoc +5 -0
- data/test/config.yaml +10 -0
- data/test/fake_std_out.rb +30 -0
- data/test/gli.reek +122 -0
- data/test/init_simplecov.rb +8 -0
- data/test/option_test_helper.rb +13 -0
- data/test/roodi.yaml +18 -0
- data/test/tc_command.rb +260 -0
- data/test/tc_compount_command.rb +22 -0
- data/test/tc_flag.rb +56 -0
- data/test/tc_gli.rb +611 -0
- data/test/tc_help.rb +223 -0
- data/test/tc_options.rb +31 -0
- data/test/tc_subcommands.rb +162 -0
- data/test/tc_switch.rb +57 -0
- data/test/tc_terminal.rb +97 -0
- data/test/test_helper.rb +13 -0
- metadata +318 -49
- data/lib/gli_version.rb +0 -3
- data/lib/support/help.rb +0 -179
- data/lib/support/initconfig.rb +0 -34
- data/lib/support/rdoc.rb +0 -119
data/test/config.yaml
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
class FakeStdOut
|
2
|
+
attr_reader :strings
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@strings = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def puts(string=nil)
|
9
|
+
@strings << string unless string.nil?
|
10
|
+
end
|
11
|
+
|
12
|
+
def write(x)
|
13
|
+
puts(x)
|
14
|
+
end
|
15
|
+
|
16
|
+
def printf(*args)
|
17
|
+
puts(Kernel.printf(*args))
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns true if the regexp matches anything in the output
|
21
|
+
def contained?(regexp)
|
22
|
+
strings.find{ |x| x =~ regexp }
|
23
|
+
end
|
24
|
+
|
25
|
+
def flush; end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
@strings.join("\n")
|
29
|
+
end
|
30
|
+
end
|
data/test/gli.reek
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
---
|
2
|
+
ControlCouple:
|
3
|
+
exclude:
|
4
|
+
- 'parse_options_helper'
|
5
|
+
- 'program_desc'
|
6
|
+
- 'program_name'
|
7
|
+
- 'name_as_string'
|
8
|
+
- 'GLI::Command'
|
9
|
+
enabled: false
|
10
|
+
UncommunicativeParameterName:
|
11
|
+
accept: []
|
12
|
+
|
13
|
+
exclude: []
|
14
|
+
|
15
|
+
enabled: false
|
16
|
+
reject:
|
17
|
+
- !ruby/regexp /^.$/
|
18
|
+
- !ruby/regexp /[0-9]$/
|
19
|
+
- !ruby/regexp /[A-Z]/
|
20
|
+
LargeClass:
|
21
|
+
max_methods: 25
|
22
|
+
exclude: []
|
23
|
+
|
24
|
+
enabled: true
|
25
|
+
max_instance_variables: 10
|
26
|
+
UncommunicativeMethodName:
|
27
|
+
accept: []
|
28
|
+
|
29
|
+
exclude: []
|
30
|
+
|
31
|
+
enabled: true
|
32
|
+
reject:
|
33
|
+
- !ruby/regexp /^[a-z]$/
|
34
|
+
- !ruby/regexp /[0-9]$/
|
35
|
+
- !ruby/regexp /[A-Z]/
|
36
|
+
LongParameterList:
|
37
|
+
max_params: 5
|
38
|
+
exclude: []
|
39
|
+
|
40
|
+
enabled: true
|
41
|
+
overrides:
|
42
|
+
initialize:
|
43
|
+
max_params: 6
|
44
|
+
FeatureEnvy:
|
45
|
+
exclude: &id001 []
|
46
|
+
|
47
|
+
enabled: false
|
48
|
+
ClassVariable:
|
49
|
+
exclude: *id001
|
50
|
+
enabled: false
|
51
|
+
BooleanParameter:
|
52
|
+
exclude: ['initialize']
|
53
|
+
enabled: true
|
54
|
+
IrresponsibleModule:
|
55
|
+
exclude: *id001
|
56
|
+
enabled: true
|
57
|
+
UncommunicativeModuleName:
|
58
|
+
accept:
|
59
|
+
- Inline::C
|
60
|
+
exclude: []
|
61
|
+
|
62
|
+
enabled: true
|
63
|
+
reject:
|
64
|
+
- !ruby/regexp /^.$/
|
65
|
+
- !ruby/regexp /[0-9]$/
|
66
|
+
NestedIterators:
|
67
|
+
ignore_iterators: []
|
68
|
+
|
69
|
+
exclude: ['GLI::App']
|
70
|
+
|
71
|
+
enabled: true
|
72
|
+
max_allowed_nesting: 3
|
73
|
+
LongMethod:
|
74
|
+
max_statements: 10
|
75
|
+
exclude:
|
76
|
+
- initialize
|
77
|
+
- parse_options
|
78
|
+
- run
|
79
|
+
- reset
|
80
|
+
enabled: true
|
81
|
+
Duplication:
|
82
|
+
allow_calls: []
|
83
|
+
|
84
|
+
exclude: ['run']
|
85
|
+
|
86
|
+
enabled: true
|
87
|
+
max_calls: 3
|
88
|
+
UtilityFunction:
|
89
|
+
max_helper_calls: 1
|
90
|
+
exclude: [ 'find_non_flag_index', 'override_default', 'proceed?', 'command_exists?' ]
|
91
|
+
|
92
|
+
enabled: true
|
93
|
+
Attribute:
|
94
|
+
exclude: []
|
95
|
+
|
96
|
+
enabled: false
|
97
|
+
UncommunicativeVariableName:
|
98
|
+
accept: []
|
99
|
+
|
100
|
+
exclude: []
|
101
|
+
|
102
|
+
enabled: true
|
103
|
+
reject:
|
104
|
+
- !ruby/regexp /^[a-z]$/
|
105
|
+
- !ruby/regexp /[0-9]$/
|
106
|
+
- !ruby/regexp /[A-Z]/
|
107
|
+
SimulatedPolymorphism:
|
108
|
+
exclude: []
|
109
|
+
|
110
|
+
enabled: true
|
111
|
+
max_ifs: 2
|
112
|
+
DataClump:
|
113
|
+
exclude: []
|
114
|
+
|
115
|
+
enabled: false
|
116
|
+
max_copies: 2
|
117
|
+
min_clump_size: 2
|
118
|
+
LongYieldList:
|
119
|
+
max_params: 3
|
120
|
+
exclude: []
|
121
|
+
|
122
|
+
enabled: true
|
data/test/roodi.yaml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Not the most strict checks, but they pass for now
|
2
|
+
AssignmentInConditionalCheck: {}
|
3
|
+
ClassLineCountCheck:
|
4
|
+
line_count: 400
|
5
|
+
ClassNameCheck:
|
6
|
+
pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
|
7
|
+
CyclomaticComplexityBlockCheck:
|
8
|
+
complexity: 5
|
9
|
+
CyclomaticComplexityMethodCheck:
|
10
|
+
complexity: 8
|
11
|
+
EmptyRescueBodyCheck: {}
|
12
|
+
ForLoopCheck: {}
|
13
|
+
MethodNameCheck:
|
14
|
+
pattern: !ruby/regexp /^[_a-z<>=\[\]|+-\/\*`]+[_a-z0-9_<>=~@\[\]]*[=!\?]?$/
|
15
|
+
ModuleNameCheck:
|
16
|
+
pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
|
17
|
+
ParameterNumberCheck:
|
18
|
+
parameter_count: 5
|
data/test/tc_command.rb
ADDED
@@ -0,0 +1,260 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
class TC_testCommand < Clean::Test::TestCase
|
5
|
+
include TestHelper
|
6
|
+
def setup
|
7
|
+
@app = CLIApp.new
|
8
|
+
@app.reset
|
9
|
+
@app.program_desc 'A super awesome program'
|
10
|
+
@app.desc 'Some Global Option'
|
11
|
+
@app.switch :g
|
12
|
+
@app.switch :blah
|
13
|
+
@app.long_desc 'This is a very long description for a flag'
|
14
|
+
@app.flag [:y,:yes]
|
15
|
+
@pre_called = false
|
16
|
+
@post_called = false
|
17
|
+
@error_called = false
|
18
|
+
@app.pre { |g,c,o,a| @pre_called = true }
|
19
|
+
@app.post { |g,c,o,a| @post_called = true }
|
20
|
+
@app.on_error { |g,c,o,a| @error_called = true }
|
21
|
+
@glob = nil
|
22
|
+
@verbose = nil
|
23
|
+
@glob_verbose = nil
|
24
|
+
@configure = nil
|
25
|
+
@args = nil
|
26
|
+
@app.desc 'Some Basic Command that potentially has a really really really really really really really long description and stuff, but you know, who cares?'
|
27
|
+
@app.long_desc 'This is the long description: "Some Basic Command that potentially has a really really really really really really really long description and stuff, but you know, who cares?"'
|
28
|
+
@app.arg_name 'first_file second_file'
|
29
|
+
@app.command [:basic,:bs] do |c|
|
30
|
+
c.desc 'be verbose'
|
31
|
+
c.switch :v
|
32
|
+
c.desc 'configure something or other, in some way that requires a lot of verbose text and whatnot'
|
33
|
+
c.default_value 'crud'
|
34
|
+
c.flag [:c,:configure]
|
35
|
+
c.action do |global_options,options,arguments|
|
36
|
+
@glob = global_options[:g] ? 'true' : 'false'
|
37
|
+
@verbose = options[:v] ? 'true' : 'false'
|
38
|
+
@glob_verbose = global_options[:v] ? 'true' : 'false'
|
39
|
+
@configure = options[:c]
|
40
|
+
@args = arguments
|
41
|
+
end
|
42
|
+
end
|
43
|
+
@app.desc "Testing long help wrapping"
|
44
|
+
@app.long_desc <<-EOS
|
45
|
+
This will create a scaffold command line project that uses @app
|
46
|
+
for command line processing. Specifically, this will create
|
47
|
+
an executable ready to go, as well as a lib and test directory, all
|
48
|
+
inside the directory named for your project
|
49
|
+
EOS
|
50
|
+
@app.command [:test_wrap] do |c|
|
51
|
+
c.action {}
|
52
|
+
end
|
53
|
+
@fake_stdout = FakeStdOut.new
|
54
|
+
@fake_stderr = FakeStdOut.new
|
55
|
+
@app.error_device=@fake_stderr
|
56
|
+
ENV.delete('GLI_DEBUG')
|
57
|
+
@original_stdout = $stdout
|
58
|
+
$stdout = @fake_stdout
|
59
|
+
@original_stderr = $stderr
|
60
|
+
$stderr = @fake_stderr
|
61
|
+
end
|
62
|
+
|
63
|
+
def tear_down
|
64
|
+
$stdout = @original_stdout
|
65
|
+
$stderr = @original_stderr
|
66
|
+
FileUtils.rm_f "cruddo.rdoc"
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_names
|
70
|
+
command = GLI::Command.new(:names => [:ls,:list,:'list-them-all'],:description => "List")
|
71
|
+
assert_equal "ls, list, list-them-all",command.names
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_command_sort
|
75
|
+
commands = [GLI::Command.new(:names => :foo)]
|
76
|
+
commands << GLI::Command.new(:names => :bar)
|
77
|
+
commands << GLI::Command.new(:names => :zazz)
|
78
|
+
commands << GLI::Command.new(:names => :zaz)
|
79
|
+
|
80
|
+
sorted = commands.sort
|
81
|
+
assert_equal :bar,sorted[0].name
|
82
|
+
assert_equal :foo,sorted[1].name
|
83
|
+
assert_equal :zaz,sorted[2].name
|
84
|
+
assert_equal :zazz,sorted[3].name
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_basic_command
|
88
|
+
args_args = [%w(-g basic -v -c foo bar baz quux), %w(-g basic -v --configure=foo bar baz quux)]
|
89
|
+
args_args.each do |args|
|
90
|
+
args_orig = args.clone
|
91
|
+
@app.run(args)
|
92
|
+
assert_equal('true',@glob,"For args #{args_orig}")
|
93
|
+
assert_equal('true',@verbose,"For args #{args_orig}")
|
94
|
+
assert_equal('false',@glob_verbose,"For args #{args_orig}")
|
95
|
+
assert_equal('foo',@configure,"For args #{args_orig}")
|
96
|
+
assert_equal(%w(bar baz quux),@args,"For args #{args_orig}")
|
97
|
+
assert(@pre_called,"Pre block should have been called for args #{args_orig}")
|
98
|
+
assert(@post_called,"Post block should have been called for args #{args_orig}")
|
99
|
+
assert(!@error_called,"Error block should not have been called for args #{args_orig}")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_command_skips_pre
|
104
|
+
@app.skips_pre
|
105
|
+
@app.skips_post
|
106
|
+
|
107
|
+
skips_pre_called = false
|
108
|
+
runs_pre_called = false
|
109
|
+
|
110
|
+
@app.command [:skipspre] do |c|
|
111
|
+
c.action do |g,o,a|
|
112
|
+
skips_pre_called = true
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Making sure skips_pre doesn't leak to other commands
|
117
|
+
@app.command [:runspre] do |c|
|
118
|
+
c.action do |g,o,a|
|
119
|
+
runs_pre_called = true
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
@app.run(['skipspre'])
|
124
|
+
|
125
|
+
assert(skips_pre_called,"'skipspre' should have been called")
|
126
|
+
assert(!@pre_called,"Pre block should not have been called")
|
127
|
+
assert(!@post_called,"Post block should not have been called")
|
128
|
+
assert(!@error_called,"Error block should not have been called")
|
129
|
+
|
130
|
+
@app.run(['runspre'])
|
131
|
+
|
132
|
+
assert(runs_pre_called,"'runspre' should have been called")
|
133
|
+
assert(@pre_called,"Pre block should not have been called")
|
134
|
+
assert(@post_called,"Post block SHOULD have been called")
|
135
|
+
assert(!@error_called,"Error block should not have been called")
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_command_no_globals
|
139
|
+
args = %w(basic -c foo bar baz quux)
|
140
|
+
@app.run(args)
|
141
|
+
assert_equal('foo',@configure)
|
142
|
+
assert_equal(%w(bar baz quux),@args)
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_defaults_get_set
|
146
|
+
args = %w(basic bar baz quux)
|
147
|
+
@app.run(args)
|
148
|
+
assert_equal('false',@glob)
|
149
|
+
assert_equal('false',@verbose)
|
150
|
+
assert_equal('crud',@configure)
|
151
|
+
assert_equal(%w(bar baz quux),@args)
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_negatable_gets_created
|
155
|
+
@app.command [:foo] do |c|
|
156
|
+
c.action do |g,o,a|
|
157
|
+
assert !g[:blah]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
exit_status = @app.run(%w(--no-blah foo))
|
161
|
+
assert_equal 0,exit_status
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_arguments_are_not_frozen
|
165
|
+
@args = []
|
166
|
+
|
167
|
+
|
168
|
+
@app.command [:foo] do |c|
|
169
|
+
c.action do |g,o,a|
|
170
|
+
@args = a
|
171
|
+
end
|
172
|
+
end
|
173
|
+
exit_status = @app.run(%w(foo a b c d e).map { |arg| arg.freeze })
|
174
|
+
assert_equal 0,exit_status
|
175
|
+
assert_equal 5,@args.length,"Action block was not called"
|
176
|
+
|
177
|
+
@args.each_with_index do |arg,index|
|
178
|
+
assert !arg.frozen?,"Expected argument at index #{index} to not be frozen"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_no_arguments
|
183
|
+
args = %w(basic -v)
|
184
|
+
@app.run(args)
|
185
|
+
assert_equal('true',@verbose)
|
186
|
+
assert_equal('crud',@configure)
|
187
|
+
assert_equal([],@args)
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_unknown_command
|
191
|
+
args = %w(blah)
|
192
|
+
@app.run(args)
|
193
|
+
assert(!@post_called)
|
194
|
+
assert(@error_called)
|
195
|
+
assert_contained(@fake_stderr,/Unknown command 'blah'/)
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_unknown_global_option
|
199
|
+
args = %w(--quux basic)
|
200
|
+
@app.run(args)
|
201
|
+
assert(!@post_called)
|
202
|
+
assert(@error_called,"Expected error callback to be called")
|
203
|
+
assert_contained(@fake_stderr,/Unknown option --quux/)
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_unknown_argument
|
207
|
+
args = %w(basic --quux)
|
208
|
+
@app.run(args)
|
209
|
+
assert(!@post_called)
|
210
|
+
assert(@error_called)
|
211
|
+
assert_contained(@fake_stderr,/ Unknown option --quux/)
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_forgot_action_block
|
215
|
+
@app.reset
|
216
|
+
@app.command :foo do
|
217
|
+
end
|
218
|
+
|
219
|
+
ENV['GLI_DEBUG'] = 'true'
|
220
|
+
assert_raises RuntimeError do
|
221
|
+
@app.run(['foo'])
|
222
|
+
end
|
223
|
+
assert_match /Command 'foo' has no action block/,@fake_stderr.to_s
|
224
|
+
end
|
225
|
+
|
226
|
+
def test_command_create
|
227
|
+
@app.desc 'single symbol'
|
228
|
+
@app.command :single do |c|; end
|
229
|
+
command = @app.commands[:single]
|
230
|
+
assert_equal :single, command.name
|
231
|
+
assert_equal nil, command.aliases
|
232
|
+
|
233
|
+
description = 'implicit array'
|
234
|
+
@app.desc description
|
235
|
+
@app.command :foo, :bar do |c|; end
|
236
|
+
command = @app.commands[:foo]
|
237
|
+
assert_equal :foo, command.name
|
238
|
+
assert_equal [:bar], command.aliases
|
239
|
+
|
240
|
+
description = 'explicit array'
|
241
|
+
@app.desc description
|
242
|
+
@app.command [:baz, :blah] do |c|; end
|
243
|
+
command = @app.commands[:baz]
|
244
|
+
assert_equal :baz, command.name
|
245
|
+
assert_equal [:blah], command.aliases
|
246
|
+
end
|
247
|
+
|
248
|
+
private
|
249
|
+
|
250
|
+
def assert_contained(output,regexp)
|
251
|
+
assert_not_nil output.contained?(regexp),
|
252
|
+
"Expected output to contain #{regexp.inspect}, output was:\n#{output}"
|
253
|
+
end
|
254
|
+
|
255
|
+
def assert_not_contained(output,regexp)
|
256
|
+
assert_nil output.contained?(regexp),
|
257
|
+
"Didn't expected output to contain #{regexp.inspect}, output was:\n#{output}"
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|